Searchkick: multi-index search

Created on 30 Sep 2013  路  26Comments  路  Source: ankane/searchkick

Searchkick should support multi-index search.

I have overcome this by using:

Model1.search("thequery", index_name: [Model1.index.name, Model2.index.name, Model3.index.name])

it works ok, but it's just wrong to have to do this.

Maybe the starting point can be #36?

enhancement

Most helpful comment

You'll need to do this in Ruby. Also, as mentioned in the comment above, please create a new issue for new questions so the 15 other subscribers to this issue aren't spammed.

All 26 comments

Multi-index search would be nice. What are your thoughts on the best way to declare indexes?

(fixed the example above, was missing 'index.name' calls)

what about something this:

Searchkick.search("thequery", [Model1, Model2, Model3], other_options)

Is this method still pending to search across multiple models. I want to use boost and autocomplete across multiple models. If searching on a particular model using index names like:

Model1.search("thequery", index_name: [Model1.index.name, Model2.index.name], boost: 'name')

then, boost will be applied only for that Model1. How can i use boost across multiple models. Like in tire, we can define it while indexing in mapping.

Quick (perhaps silly) question, how can I get the index name for a model?

It's now Model.searchkick_index.name.

Holy moly that was a fast response. Much appreciated.

Haha, no problem - right place, right time.

Ok second question; how can I get the current full index name?

Test.searchkick_index.name is returning "test_development"

But my actual index_name is "test_development_20140219162300398" etc. I need the full name in order to use it alongside index_name: when searching across multiple models.

You should use the alias when searching across models - it's more robust and gives you the same results.

Ah my bad, I had mistyped an index name. Thanks again.

+1 to multi-index search. @liberatiluca's suggestion would be awesome.

The workaroud which is on the very top of the page doesn't work because index_name option is useless now. Index name is set explicitly index: searchkick_index.name before sending to client

I used this for an autocomplete field to match multiple models (indexes) :

results = []

[Model1, Model2, Model3, Model4].each do |model|
  query = Searchkick::Query.new model, params[:query], load: false, fields: [{name: :text_start}], limit: 10
  results = results.concat query.execute.response['hits']['hits']
end

results.sort_by! { |r| r['_score'] }.reverse!

render json: {
  all: results.map { |r| { value: r['_source']['name'] } }.first(10)
}

It shouldn't be too much of a hastle to add a method that uses this logic to the Searchkick::Query class. I'll take a deeper look into this when I have the time.

@amenzhinsky Oops, just fixed. Need to add a test for that. https://github.com/ankane/searchkick/commit/cec8c5882cd609b906a69b6f398df05ce7741d40

@jdurand What's the advantage to this approach vs the index_name option?

@ankane I never got the index_name approach to work and, if I understood correctly, this approach would not let you define different search criterion (ie: boost) for each model.
My approach does 4 separate queries and assemble the results, so we could do something like :

[{model: Model1, boost: 'popularity'}, {model: Model2, boost: 'popularity'}].each do |params|
  ...

I'm just tossing ideas around...

Has this been implemented into searchkick yet?

Another solution for the multimodel search (this will search across all searchkick indexes)
index_name: Searchkick.client.indices.get_aliases.keys,

Is it possible to specify an includes option for each model type doing a multisearch that way?

Hi,
I'm a beginner with rails

Model1.search(params[:query], index_name: [Model1.searchkick_index.name, Model2.searchkick_index.name])

I tried using it like this but all the results comes only from Model1. Is there anyway to get results from both models.

Both models have different attributes.

:+1:

The solution I have found comes from using the Searchkick class as my method

# app/models/foo.rb
class Foo
  searchkick
  def search_data
    { name: name }
  end
  def name
  end
end

# app/models/bar.rb
class Bar
  searchkick
  def search_data
    { name: name }
  end
  def name
  end
end
> Foo.reindex
> Bar.reindex
results = Searchkick.search('query')

This will search every index with the name field.


If you want to search just specific fields

# update the `search_data` method to contain your other field
# app/models/foo.rb
class Foo
  searchkick
  def search_data
    { name: name,
      description: description }
  end
  def name
  end
  def description
  end
end
> Foo.reindex
# you can then define which fields to search
results = Searchkick.search('query', fields: ['name', 'description'])

# Cool part is, if one model/index has a field the others don't, searchkick will still work as expected
results = Searchkick.search('query', fields: ['name', 'description', 'unique_field'])

# if you want to boost a certain field, put a carrot to power
results = Searchkick.search('query', fields: ['name^10', 'description'])

This feature was added to the documentation in July: https://github.com/ankane/searchkick/commit/bd12de702bbe38fa660e8156ad1d8b7bfa30bb25

I'm unsure when the code was implemented.

Does anyone know if it's possible to search multiple indices (ie Searchkick.search "milk", index_name: [Product, Category]) and apply different order and limit to the different indices?

@MrHubble You'll need use multi search instead (basically, two separate queries) if you want different orders and limits.

https://github.com/ankane/searchkick#multi-search

Closing this issue as multi-index search is now supported. Please create a new issue if I missed anything or there are future questions.

@ankane Sorry to bother, but how can I sort results by _score in a multi_search example?

user_results = User.search(
  "*",
  limit: 20,
  execute: false
)
organization_results = Organization.search(
  "*",
  limit: 40,
  execute: false,
  order: { updated_at: :desc}
)
Searchkick.multi_search([user_results, organization_results])

I'd like to see organizations with higher score before than users. Thanks in advance

You'll need to do this in Ruby. Also, as mentioned in the comment above, please create a new issue for new questions so the 15 other subscribers to this issue aren't spammed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

netwire88 picture netwire88  路  3Comments

gerrywastaken picture gerrywastaken  路  3Comments

mehulkar picture mehulkar  路  5Comments

tomajask picture tomajask  路  4Comments

carolliu picture carolliu  路  3Comments