Bilingual site: exclude fields set from query


#1

Hi all,

Is there a way to have searches no use some indexed fields, when
processing a query?

context:
I have a model Foo that holds some information in two languages :

  • text1_nl, text2_nl, text3_nl
    and
  • text1_en, text2_en, text3_en
    Some other fields are common to both languages and indexed as well
  • first_name, last_name

Depending on the visitor language choice I need to exclude the first
three, or last three fields when query processing. Is this doable
relatively simply?
I guess I could use two indexes, but I’d like to keep using
acts_as_ferret if possible.

TIA.

Alain R.


#2

I would setup your models differently, using Single-Table Inheritance
(STI). (You can get more info on it by Googling “rails single table
inheritance”.) For your example, you’d have a table with columns like:

id, type, first_name, last_name, text1, text2, text3

Then, you’d have a model like:

class Text << ActiveRecord::Base
acts_as_ferret(… declare all fields here )
end

You’d then subclass this with two other classes:

class EnglishText << Text
end

class DutchText << Text
end

Then, to search one or the other, use:

EnglishText.find_by_contents(“english query”)

DutchText.find_by_contents(“dutch query”)

That’s a rough idea without exact code, but it should hopefully get you
started.

Thanks,

Doug


#3

Doug

I would setup your models differently, using Single-Table Inheritance

STI would be impractical (I don’t want to add a useless “type”
column), but plain inheritance sounds like a very good idea.

class Text << ActiveRecord::Base
acts_as_ferret(… declare all fields here )
end>
You’d then subclass this with two other classes:

class EnglishText << Text
end
class DutchText << Text
end

I guess you meant :

class Text << ActiveRecord::Base
end
class EnglishText << Text
acts_as_ferret :fields => [name, text_en]
end
class DutchText << Text
acts_as_ferret :fields => [name, text_nl]
end

That would indeed allow to call :

EnglishText.find_by_contents(“english query”)
DutchText.find_by_contents (“dutch query”)

Clean and simple.
Thanks a lot.

Alain R.

http://blog.ravet.com


#4

On Wed, May 16, 2007 at 08:55:46PM +0200, Alain R. wrote:

Some other fields are common to both languages and indexed as well

  • first_name, last_name

Depending on the visitor language choice I need to exclude the first
three, or last three fields when query processing. Is this doable
relatively simply?
I guess I could use two indexes, but I’d like to keep using
acts_as_ferret if possible.

A query string like

text1_nl|text2_nl|text3_nl|first_name|last_name:query

will only search for query in the named fields.

Jens


Jens Krämer
webit! Gesellschaft für neue Medien mbH
Schnorrstraße 76 | 01069 Dresden
Telefon +49 351 46766-0 | Telefax +49 351 46766-66
removed_email_address@domain.invalid | www.webit.de

Amtsgericht Dresden | HRB 15422
GF Sven Haubold, Hagen Malessa


#5

Jens,

A query string like
text1_nl|text2_nl|text3_nl|first_name|last_name:query
will only search for query in the named fields.

Thanks.

Is this the proper syntax for multi-words queries:

first_name|last_name:(jo* OR va*)
?

Alain


#6

Hey Alain,

finally jumped on board? :slight_smile: hope to see you in berlin in a few month …

Is this the proper syntax for multi-words queries:

first_name|last_name:(jo* OR va*)

i would suggest to use the OO-Syntax for more complex queries … like
that:

query = BooleanQuery.new
[ :first_name, :last_name ].each do |key|
query.add_query( PrefixQuery.new( key, ‘jo’ ), :should )
end

for a people-livesearch, i do something like [1]:

def build_livesearch_query( fields, q )
q = filter_special_characters( q ) # custom method
query = BooleanQuery.new
fields.uniq.each do |field|
sq = SpanNearQuery.new(:in_order => true, :slop => 1)
terms = analyze_query(q, field) # custom method
terms.each do |term|
sq << SpanPrefixQuery.new( field, term )
end
query << sq
end
query
end

i call that like

build_livesearch_query( [:first_name, :last_name, :email, q ) # q
is an array of search words

Ben

[1] all of the code at http://bugs.omdb.org/browser/trunk/lib/omdb/
ferret/local_search.rb


#7

I’m refactoring/upgrading an “old” (1-year) app, where I used to do
all the ferret index stuff myself (callbacks, queries, …), to the
mucho simpler interface offered by acts_as_ferret. AFAIK, aaf only
works with string queries, so if there is a string-based solution that
works, I’d rather use this one. If there is none, I’ll bite the bullet
and follow your advice. “A man’s got to do, what a man’s got to do”

Alain,

i’m no AAF expert, but afaik most methods of aaf are using
find_id_by_contents… which is accepting a query parameter…

that query parameter gets forwarded to ferrets own search_each.

search_each accepts strings or ferret query objects… so i would
assume that you can pass a OO-Query to AAF. And anything else
would have surprised me… as Jens code is quite sophisticated :slight_smile:

Ben


#8

Hi Ben,

Hey Alain,
finally jumped on board? :slight_smile: hope to see you in berlin in a few
months

Can’t wait to register. My credit card is on the starting-blocks.

Is this the proper syntax for multi-words queries:
first_name|last_name:(jo* OR va*)

i would suggest to use the OO-Syntax for more complex queries … like
query = BooleanQuery.new

I’m refactoring/upgrading an “old” (1-year) app, where I used to do
all the ferret index stuff myself (callbacks, queries, …), to the
mucho simpler interface offered by acts_as_ferret. AFAIK, aaf only
works with string queries, so if there is a string-based solution that
works, I’d rather use this one. If there is none, I’ll bite the bullet
and follow your advice. “A man’s got to do, what a man’s got to do”

Alain


Alain R.