Tom Beddard
2006-Sep-12 15:07 UTC
[Ferret-talk] Querying against numeric fields? e.g. price:( >= min_price)
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 -- Posted via http://www.ruby-forum.com/.
David Balmain
2006-Sep-12 19:11 UTC
[Ferret-talk] Querying against numeric fields? e.g. price:( >= min_price)
On 9/13/06, Tom Beddard <tom at subblue.com> wrote:> 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? > > ThanksHi 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
Yaxm Yaxm
2007-Apr-30 02:27 UTC
[Ferret-talk] Querying against numeric fields? e.g. price:( >= min_pri
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 -- Posted via http://www.ruby-forum.com/.
Yaxm Yaxm
2007-May-07 03:47 UTC
[Ferret-talk] Querying against numeric fields? e.g. price:( >= min_pri
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 Balmain wrote:> On 9/13/06, Tom Beddard <tom at subblue.com> 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-- Posted via http://www.ruby-forum.com/.