Using acts_as_ferret I’m trying to do a query like:
active:(true) title|body:(#{params[:s]}) product_price:( >=
#{params[:min]})
Where I want to return only the active products that contain the search
term in the title or body and has a minimum price >= params[:min]
I’m finding that even though I’m indexing the product price as an
integer (so no .00 to cause confusion) I’m getting results in the 50
value range as well as 500 if I set the min price as 500. I presume
ferret is doing the price as a string comparison, but is there any way
to make it do a numeric match?
Thanks
On 9/13/06, Tom B. [email protected] wrote:
integer (so no .00 to cause confusion) I’m getting results in the 50
value range as well as 500 if I set the min price as 500. I presume
ferret is doing the price as a string comparison, but is there any way
to make it do a numeric match?
Thanks
Hi Tom,
You need to pad all numbers to a fixed width when adding them to the
index as well as when querying the index. Usually you’d write the code
to do this yourself. I’ve recently come up with another way to do
this.
require 'ferret'
module Ferret::Analysis
class IntegerTokenizer
def initialize(num, width)
@num = num.to_i
@width = width
@done = false
end
def next
if @done
return nil
else
@done = true
puts Token.new("%0#{@width}d" % @num, 0, @width)
return Token.new("%0#{@width}d" % @num, 0, @width)
end
end
def text=(text)
@num = text.to_i
@done = false
end
end
class IntegerAnalyzer
def initialize(width)
@width = width
end
def token_stream(field, input)
return IntegerTokenizer.new(input, @width)
end
end
end
include Ferret::Analysis
analyzer = PerFieldAnalyzer.new(StandardAnalyzer.new)
analyzer[:num] = IntegerAnalyzer.new(5)
index = Ferret::Index::Index.new(:analyzer => analyzer)
docs = [
{:num => 1, :data => "yes"},
{:num => 1, :data => "no"},
{:num => 10, :data => "yes"},
{:num => 10, :data => "no"},
{:num => 100, :data => "yes"},
{:num => 100, :data => "no"},
{:num => 1000, :data => "yes"},
{:num => 1000, :data => "no"}
]
docs.each { |d| index << d }
puts index.process_query('data:yes AND num:[10 100]')
puts index.search('data:yes AND num:[10 100]')
This will only work with the working copy of Ferret from the
subversion repository. I’m still not convinced that this is the best
way to do it.
Cheers,
Dave
Hi, David.
Can you tell me where to include your codes for integration with
Rails(acts_as_ferret)?
I just want to pad 0’s to do numeric comparision
I am pretty new to Rails and Ferret.
Thanks.
Yaxm
This doesn’t work because “10” is used.
puts index.process_query('data:yes AND num:[10 100]')
puts index.search('data:yes AND num:[10 100]')
One must pad the integer with zero’s just like the analyzer:
puts index.process_query(‘data:yes AND num:[00010 00100]’)
puts index.search(‘data:yes AND num:[00010 00100]’)
To use this in a Rails app:
include the IntegerAnalyzer defnition in a file.
then require the file in your model.
inside your model class:
include Ferret::Analysis
analyzer = PerFieldAnalyzer.new(StandardAnalyzer.new)
analyzer[:num] = IntegerAnalyzer.new(5)
analyzer[:blah_field] = IntegerAnalyzer.new(5)
acts_as_ferret(
{:fields => [:blah_field] }
, {:analyzer => analyzer}
David B. wrote:
On 9/13/06, Tom B. [email protected] wrote:
integer (so no .00 to cause confusion) I’m getting results in the 50
value range as well as 500 if I set the min price as 500. I presume
ferret is doing the price as a string comparison, but is there any way
to make it do a numeric match?
Thanks
Hi Tom,
You need to pad all numbers to a fixed width when adding them to the
index as well as when querying the index. Usually you’d write the code
to do this yourself. I’ve recently come up with another way to do
this.
require 'ferret'
module Ferret::Analysis
class IntegerTokenizer
def initialize(num, width)
@num = num.to_i
@width = width
@done = false
end
def next
if @done
return nil
else
@done = true
puts Token.new("%0#{@width}d" % @num, 0, @width)
return Token.new("%0#{@width}d" % @num, 0, @width)
end
end
def text=(text)
@num = text.to_i
@done = false
end
end
class IntegerAnalyzer
def initialize(width)
@width = width
end
def token_stream(field, input)
return IntegerTokenizer.new(input, @width)
end
end
end
include Ferret::Analysis
analyzer = PerFieldAnalyzer.new(StandardAnalyzer.new)
analyzer[:num] = IntegerAnalyzer.new(5)
index = Ferret::Index::Index.new(:analyzer => analyzer)
docs = [
{:num => 1, :data => "yes"},
{:num => 1, :data => "no"},
{:num => 10, :data => "yes"},
{:num => 10, :data => "no"},
{:num => 100, :data => "yes"},
{:num => 100, :data => "no"},
{:num => 1000, :data => "yes"},
{:num => 1000, :data => "no"}
]
docs.each { |d| index << d }
puts index.process_query('data:yes AND num:[10 100]')
puts index.search('data:yes AND num:[10 100]')
This will only work with the working copy of Ferret from the
subversion repository. I’m still not convinced that this is the best
way to do it.
Cheers,
Dave