I created a search engine in my rails 4 app that was working great, but I am having a very hard time getting the asciifolding filter to work. My model has a lot of terms with accents which will not come up unless they're spelled exactly right, ie: I want a search for "Rodriguez" to display results with "Rodríguez." I have tried to follow many different examples but for some reason when I reset my database with the following code, the search won't work at all (I don't get an error but nothing comes up regardless of the query).
Here is my model:
class Product < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
settings :analysis => {
:analyzer => {
:default => {
:tokenizer => "standard",
:filter => ["standard", "asciifolding"]
}
}
} do
mapping do
indexes :id, type: 'integer', index: :not_analyzed
indexes :name, boost: 5, analyzer: 'default'
indexes :website, index: :not_analyzed
indexes :price, type: 'integer', index: :not_analyzed
indexes :artist, boost: 3, analyzer: 'default'
indexes :company, boost: 4, analyzer: 'default'
indexes :date, type: 'date', index: :not_analyzed
end
end
def self.search(params)
tire.search(page: params[:page], per_page: 12) do
query { string params[:query], default_operator: "AND" } if params[:query].present?
end
end
Before testing, I clear the database with:
rake db:setup
Then I run:
rake environment tire:import CLASS=Product FORCE=true
I have looked at many different resources including the elasticsearch and tire documentation, but for whatever reason (i am anticipating a stupid mistake) it simply won't work. Small note, to populate my database I have been importing a csv file, but I don't see why this would effect anything, especially considering nothing is coming up in the search in this form (it works fine sans the accent problem when I delete the settings part and just have the mapping block and search method). Do I need to call some sort of Tire.index and import? Any help is appreciated!
UPDATE
So I made an edit to the search query which fixed the problem but raised a new one:
def self.search(params)
tire.search(page: params[:page], per_page: 12) do
query { string params[:query], analyzer: :search_analyzer, :default_field => 'name' } if params[:query].present?
end
end
By identifying a default field, I can now search accent agnostic, but now my search is limited to just the name and I cannot receive results for other indexed attributes that were working previously. Does anyone know how to set multiple default fields?
This is example that I use in production. It's not solution to your problem but it will get you off the ground. My code is using ICU plugin for icu_folding, shingle_filter, multi_field and Tire. Also note that Tire is retired since september 2013 and that you should be using elasticsearch-ruby or elasticsearch-rails if its a new project. With this code I can have autocomplete with cases like Rod
finding Rodríguez
.
class Profile
# ...
include Tire::Model::Persistence
# I'm also using ES as persistance storage.
include Tire::Model::DynamicPersistence
property :title, analyzer: 'snowball', type: :multi_field,
fields: {
title: {
type: 'string',
boost: 20.0,
search_analyzer: "autocomplete_search_analyzer",
index_analyzer: "autocomplete_indexer_analyzer"
},
completed: {
type: 'string',
boost: 15.0,
search_analyzer: "autocomplete_search_analyzer",
index_analyzer: "autocomplete_indexer_analyzer"
}
}
CONFIGURATION = {
settings: {
analysis: {
analyzer: {
shingle_analyzer: {
tokenizer: "keyword",
filter: ["icu_folding", "lowercase", "shingle_filter"]
},
sx_index_analyzer: {
tokenizer: "standard",
filter: ["icu_folding", "lowercase"]
},
sx_search_analyzer: {
tokenizer: "standard",
filter: ["icu_folding", "lowercase"]
}
},
filter: {
shingle_filter: {
type: "shingle",
min_shingle_size: 2,
max_shingle_size: 5
}
}
}
},
mappings: {
profile: {
"_all" => {
enabled: true,
index_analyzer: "sx_index_analyzer",
search_analyzer: "sx_search_analyzer"
},
properties: {
title: {
type: "multi_field",
fields: {
title: {
type: "string",
store: "yes",
boost: 20.0
#index_analyzer: "sx_index_analyzer",
#search_analyzer: "sx_search_analyzer"
},
sortable: {
type: "string",
index: "analyzed"
},
autocomplete: {
type: "string",
index_analyzer: "shingle_analyzer",
boost: 15.0
},
}
}
}
}
}
}
def self.rebuild_index
Tire.index Profile.index_name do
delete if Profile.index.exists?
create Profile::CONFIGURATION
end
end
end
Hope it helps!