Searchkick: Reindex on model in multitenancy through default scope app
That's interesting with regards to scopes. I think that doesn't have any bearing on your issue though, because the Apartment gem is not using scopes to separate out your tenants, it's using postgres schemas (you're using pg right?) which makes the records in the other schemas unqueryable entirely because they aren't even visible unless you're in the global tenant. Does that sound right?
My apologies Chris, I see I've created some confusion with my original post. When I said "I followed the suggested article in the readme", I was referring to the Searchkick readme where it says "Check out this great post on the Apartment gem. Follow a similar pattern if you use another gem". I never explicitly stated that I wasn't using the Apartment gem, which I am not.
I set up multitenancy in my app following this railscast, which uses scopes.
Ohhhh! My bad! Hahaha I was assuming you were using apartment. This all makes a ton more sense now!!
Yeah, my apologies for taking so long to clear this up. Are you familiar with that implementation? Unrelated to elasticsearch but I've read:
I don't like the default_scope for the reason that it is not threadsafe. The user id is stored in a class variable, which means that two or more concurrent users in your app will break this unless you use Unicorn or some other web server that makes sure no more than one single client connection will access the same thread.
http://stackoverflow.com/a/22534147/1299792
I've responded to that comment with:
In the railscast Ryan said: "We can find another potential issue in the Tenant model where we call cattr_accessor for the current_id attribute. While this is convenient it’s not really thread-safe so we might want to do something like this instead: Thread.current[:tenant_id] = id, Now we have getter and setter methods that use Thread.current to set the value which is more thread-safe". Do you still feel using default_scope with this implementation is not thread-safe?
Hi Chris,
Unrelated to all of the multitenancy and reindexing talk, how come you didn't need to use autocomplete: true
in your search query and also set the autocomplete
field in your search data? I've been struggling to get my search queries to match as I wanted and it only worked when I incorporated autocomplete
. I previously tried this like word_start
, word_end
etc with no luck.
Thanks.
Searchkick's docs for autocomplete show using this which should tell it to index those with the word_start option, so I believe that's all I did.
class Book < ActiveRecord::Base
searchkick word_start: [:title, :author]
end
https://github.com/ankane/searchkick/#instant-search--autocomplete
You doing something different?
Yeah, for me if I search for a Product for number "pm07" then I only want that product returned, I don't want "pm01" or "pm03" returned. I was only able to get this to work by using autocomplete:true
but I can't figure out why.
If we look at what's created for word_start
we find:
Mapping
"product_number" : {
"type" : "keyword",
"fields" : {
"analyzed" : {
"type" : "text"
},
"word_start" : {
"type" : "text",
"analyzer" : "searchkick_word_start_index"
}
},
"ignore_above" : 256
},
Analyzer
searchkick_word_start_index: {
type: "custom",
tokenizer: "standard",
filter: ["lowercase", "asciifolding", "searchkick_edge_ngram"]
},
searchkick_edge_ngram filter
searchkick_edge_ngram: {
type: "edgeNGram",
min_gram: 1,
max_gram: 50
},
If we look at what's created for autocomplete
we find:
Mapping
"product_number" : {
"type" : "keyword",
"fields" : {
"analyzed" : {
"type" : "text"
},
"autocomplete" : {
"type" : "text",
"analyzer" : "searchkick_autocomplete_index"
}
},
"ignore_above" : 256
}
Analyzer
"searchkick_autocomplete_index" : {
"filter" : ["lowercase","asciifolding"],
"type" : "custom",
"tokenizer" : "searchkick_autocomplete_ngram"
},
Tokenizer
tokenizer: {
searchkick_autocomplete_ngram: {
type: "edgeNGram",
min_gram: 1,
max_gram: 50
}
}
So I think both word_start
and autcomplete
use lowercase, asciifolding and edgeNGram.
The difference I think comes in the search query and the use of autocomplete: true
. So with word_start we can simply use:
Product.search "pm07"
whereas with autocomplete we have:
Product.search "pm07", autocomplete: true
which I think then uses the following code:
if options[:autocomplete]
payload = {
multi_match: {
fields: fields,
query: term,
analyzer: "searchkick_autocomplete_search"
}
}
searchkick_autocomplete_search: {
type: "custom",
tokenizer: "keyword",
filter: ["lowercase", "asciifolding"]
},
At this point in time I can't figure out what payload
code is called/used for word_start
and how it differs to that used by autocomplete
I posted the comment above in an existing Searchkick issue and the author responded with:
My guess is you need to use misspellings: false. Also, to help with debugging queries and mappings, you can use the recently added:
Product.search("something", debug: true)
Awesome to have the debugging option, and it makes sense that you don't want misspellings in that situation. Search is complex. Haha