開発環境と本番環境でSearchkickによる検索結果が違う
解決したいこと
開発環境と本番環境でSearchkickによる検索結果が違う。
RailsのElasticsearchのGem「Searchkick」を使って検索機能を実装しました。
しかしHerokuにデプロイした本番環境の検索結果と、ローカルサーバーでの検索結果が異なります。
具体的には、なぜかローカル環境だけ検索時のscoreが10倍されているようで、searchkickのクエリーとしてmin_score: 1
としているフィルターをくぐり抜けてしまって関係ないものがヒットしてしまっているようです。
以下コードのmin_score
の値を10倍したりして突き止めました。
home_controller.rb
def products_query
if params[:q].present?
Product.search(params[:q], fields: [:keywords], body_options: {min_score: 1}, operator: "or", order: [{ id: :asc }])
else
Product.all.order(id: "desc")
end
end
product.rb
class Product < ApplicationRecord
searchkick language: "japanese"
def search_data
{
id: id,
keywords: keywords
}
end
end
現在はproduction側が求める挙動になっているのでいいですが、後々のデプロイで問題になりそうなので原因を把握しておきたいです‥。もしお詳しい方がいたらご教授いただけると嬉しいですm(_ _)m
該当するソースコード
Railsコンソールでの検索実行結果
productionとローカルどちらも、boost
が1と10のクエリを2回に分けて呼ばれているのが気になります。
production
> Product.search("加湿機", fields: [:keywords], body_options: {min_score: 1}, operator: "or", order: [{ id: :asc }], debug: true)
Elasticsearch Query
curl https://xxx:yyy@zzz.us-east-1.bonsaisearch.net:443/products_production/_search?pretty -H 'Content-Type: application/json' -d '{"query":{"bool":{"should":[{"dis_max":{"queries":[{"match":{"keywords.analyzed":{"query":"加湿機","boost":10,"operator":"or","cutoff_frequency":0.001,"analyzer":"searchkick_search"}}},{"match":{"keywords.analyzed":{"query":"加湿機","boost":1,"operator":"or","analyzer":"searchkick_search","fuzziness":1,"prefix_length":0,"max_expansions":3,"fuzzy_transpositions":true}}}]}}]}},"sort":[{"id":"asc"}],"timeout":"11s","_source":false,"size":10000,"min_score":1}'
Elasticsearch Results
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "6",
"_score": null,
"sort": [
6
]
},
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "7",
"_score": null,
"sort": [
7
]
},
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "8",
"_score": null,
"sort": [
8
]
},
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "9",
"_score": null,
"sort": [
9
]
},
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "10",
"_score": null,
"sort": [
10
]
},
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "11",
"_score": null,
"sort": [
11
]
},
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "12",
"_score": null,
"sort": [
12
]
}
]
}
}
localhost:3000
> Product.search("加湿機", fields: [:keywords], body_options: {min_score: 1}, operator: "or", order: [{ id: :asc }], debug: true)
Elasticsearch Query
curl http://localhost:9200/products_development/_search?pretty -H 'Content-Type: application/json' -d '{"query":{"bool":{"should":[{"dis_max":{"queries":[{"match":{"keywords.analyzed":{"query":"加湿機","boost":10,"operator":"or","analyzer":"searchkick_search"}}},{"match":{"keywords.analyzed":{"query":"加湿機","boost":1,"operator":"or","analyzer":"searchkick_search","fuzziness":1,"prefix_length":0,"max_expansions":3,"fuzzy_transpositions":true}}}]}}]}},"sort":[{"id":"asc"}],"timeout":"11s","_source":false,"size":10000,"min_score":1}'
Elasticsearch Results
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 12,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "products_development_20201213192742895",
"_type": "_doc",
"_id": "1",
"_score": null,
"sort": [
1
]
},
// 中略
{
"_index": "products_development_20201213192742895",
"_type": "_doc",
"_id": "12",
"_score": null,
"sort": [
12
]
}
]
}
}
kibana console (bonsai console)
production
{
// "min_score": 1, 本来はこの行を入れてスコア1以上にフィルターします
"query": {
"multi_match": {
"fields": [ "keywords.analyzed"],
"query": "加湿機"
}
}
}
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 12,
"relation": "eq"
},
"max_score": 1.4967165,
"hits": [
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "6",
"_score": 1.4967165,
"_source": {
"id": 6,
"keywords": "{加湿器,加湿機,気化式,ナノイー}"
}
},
// 中略
{
"_index": "products_production_20201213090523599",
"_type": "_doc",
"_id": "3",
"_score": 0.4183664,
"_source": {
"id": 3,
"keywords": "{ドラム式乾燥機付き洗濯機,ドラム式洗濯乾燥機,ビッグドラム}"
}
}
]
}
}
local:5601
GET /products_development/_search
{
// "min_score": 1, 本来はこの行を入れてスコア1以上にフィルターします
"query": {
"multi_match": {
"fields": [ "keywords.analyzed"],
"query": "加湿機"
}
}
}
{
"took" : 16,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 12,
"relation" : "eq"
},
"max_score" : 1.3637168,
"hits" : [
{
"_index" : "products_development_20201213192742895",
"_type" : "_doc",
"_id" : "6",
"_score" : 1.3637168,
"_source" : {
"id" : 6,
"keywords" : "{加湿器,加湿機,気化式,ナノイー}"
}
},
// 中略
{
"_index" : "products_development_20201213192742895",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.34109813,
"_source" : {
"id" : 3,
"keywords" : "{ドラム式乾燥機付き洗濯機,ドラム式洗濯乾燥機,ビッグドラム}"
}
}
]
}
}
自分で試したこと
-
rake searchkick:reindex:all
でのインデックスし直し - kibanaで
DELETE /products_development_20201213192742895
してからのインデックスし直し
環境
Gemfile.rb
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.7.1'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3', '>= 6.0.3.2'
# Use sqlite3 as the database for Active Record
group :development, :test do
gem 'sqlite3', '~> 1.4'
end
group :production do
gem 'pg', '0.20.0'
end
gem 'google-analytics-rails'
gem 'meta-tags'
gem 'elasticsearch', '7.2.0'
gem 'searchkick'
# 以下省略
思い当たる原因
- ローカルとstagingのDBにproductionのデータをCSVにしてインポートした(前に上書きしようとして
products_pkey
がおかしくなったことがあった) - マイグレーションファイルでカラムを追加→削除した際にマイグレーションファイルだけ削除したが
schema.rb
の変更をそのままコミットしプッシュした(versionだけ書き換わったもの) - そもそも
body_options: {min_score: 1}
はスコア1以上に絞るクエリーではない?
0