How to make searchkick search integer fields?
Let's say i have a Book model with three properties namely name:string, author:string and pages:integer.
I want to search according to pages field. Right now if i use a query like below it works for string fields i.e name and author but it doesnt work for pages field which is of integer type.
Book.search(q,
misspellings: { below: 5 },
fields: [:name, :author, :pages],
order: { name: 'asc' },
page: params[:page],
per_page: 20)
I go to console and just searched Book.search(120, fields: [:pages]) and it returns empty result even though there are records with pages 120. Why is searchkick not searching for integer fields? I appreciate any help to this dilemma i am facing. Thanks!
I fixed it with this
In Book model
def search_data
{
name: name,
author: author,
pages: pages.to_s
}
end
Related
I have an Autocomplete class with a results method that queries two different models to return data. It partially works great, but with one major issue.
def results
Searchkick.search #query, index_name: [Location, DiveCenter]
end
I need to limit the hits returned from the index DiveCenter because of the way I have the index set up. It's set up this way because a user will either click on a DiveCenter and be taken to the DiveCenter show page OR click on a location and be taken to /search?(city | country)=value.
searchkick searchable: [:name, :city, :state, :country]
def search_data
{
name: name,
city: location.city,
state: location.state,
country: location.country
}
end
So basically, what I need is this:
def results
Searchkick.search #query, index_name: [Location, DiveCenter], fields: ['location.city', 'location.state', 'location.country', 'dive_center.name']
end
Elasticsearch doesn't provide a way to limit results from a single index.
One approach is to filter the results in Ruby.
Another approach is to use multi search to limit the results for dive centers.
I use the following code to search using SearchKick:
Book.search(q,
misspellings: { below: 5 },
fields: [:name, :author, :pages],
order: { name: 'asc' },
page: params[:page],
per_page: 20)
When I search name and author it works fine.
However, when I search 130 for page it doesn't search the field.
name and author are string fields of a Book model, and page is an integer field.
My guess is the 130 is coming through as a string, and it is incorrectly trying to match the integer.
How can I make it so that I can search based on page numbers?
Have you tried calling to_i on params[:page]?
Book.search(q,
misspellings: { below: 5 },
fields: [:name, :author, :pages],
order: { name: 'asc' },
page: params[:page]&.to_i,
per_page: 20)
If you're right and it is comparing integer to string, this would fix it.
So, I have the following
Dialogue.rb
belongs_to Chapter
# Get the total number of dialogues in a chapter, then see what number we are
def order_in_chapter
chapter.dialogues.index(self) + 1
end
Chapter.rb
has_many Stories
Chapters also have an "order number" so we know what order to show the chapters in.
The problem is that on active admin, the business requirement is to sort by chapter, then dialogue number. Sorting by multiple indexes isn't too difficult, but sorting by an index and then sorting the returning association by the return value of a method seems impossible?
For reference:
ActiveAdmin.register Dialogue do
controller do
def scoped_collection
super.includes :chapter, :character
end
end
index do
column :chapter, sortable: "chapters.order_num"
end
This sorts the chapters correctly (chapter 1, then 2, then 3, etc.) but the dialogues within those chapters are returned in a jumbled order when I want for them to be returned by the dialogue.order_in_chapter method.
Is there a way to do this?
The pseudocode that I need is like:
StoryVoice.order(chapter: :asc).then_by(order_in_chapter: :asc)
Found a way:
column :chapter,
sortable: lambda { Chapter.includes(:dialogue)
.order('dialogue.order_in_chapter desc') }
I'm trying to sort my ES results by 2 fields: searchable and year.
The mapping in my Rails app:
# mapping
def as_indexed_json(options={})
as_json(only: [:id, :searchable, :year])
end
settings index: { number_of_shards: 5, number_of_replicas: 1 } do
mapping do
indexes :id, index: :not_analyzed
indexes :searchable
indexes :year
end
end
The query:
#records = Wine.search(query: {match: {searchable: {query:params[:search], fuzziness:2, prefix_length:1}}}, sort: {_score: {order: :desc}, year: {order: :desc}}, size:100)
The interesting thing in the query:
sort: {_score: {order: :desc}, year: {order: :desc}}
I think the query is working well with the 2 sort params.
My problem is the score is not the same for 2 documents with the same name (searchable field).
For example, I'm searching for "winery":
You can see a very different score, even if the searchable field is the same. I think the issue is due to the ID field (it's an UUID in fact). Looks like this ID field influences the score.
But in my schema mapping, I wrote that ID should not be analyzed and in my ES query, I ask to search ONLY in "searchable" field, not in ID too.
What did I miss to math the same score for same fields ? (actually, sorting by year after score is not useful cos' scores are different for same fields)
Scores are different, because they are calculated independently for each shard. See here for more info.
I am indexing some of my data with searchkick (https://github.com/ankane/searchkick) as an array and it works almost fine :)
def search_data
{isbn: isbn,
title: title,
abstract_long: abstract_long,
authors: authors.map(&:name)}
end
The field I'm interested in is authors.
What I'd like to accomplish is to search for "Marias" and find all the authors that actually have that exact string in their surname like (Javier Marias) and not all the Maria/Mario/Marais that Searchkick returns, and have them with a much bigger priority.
This is how I search right now
Book.search(#search_key,
fields: [:authors, :title, {isbn: :exact}],
boost_by: {authors: 10, title: 5, isbn: 1})
Is this possible at all? TIA
In Elasticsearch it has a regular match to deal with this case, but abandoned by Searchkick.
You could choose a walk around way for this case:
def search_data
{
isbn: isbn,
title: title,
abstract_long: abstract_long,
author_ids: authors.map(&:id)
}
end
For search:
author_ids = Author.where(surname: 'Marias').map(&:id)
Book.search(
#search_key,
where: {author_ids: {in: author_ids}},
fields: [:title, {isbn: :exact}],
boost_by: {title: 5, isbn: 1}
)