mappingにてとあるfieldにmulti fieldを追加をした後、partial reindexではなぜ期待する挙動が得られないか
はじめに
こんにちは!GMOペパボでwebアプリケーションエンジニアをしている、kazuです。
本記事は、GMOペパボの2023年度のアドベントカレンダー21日目の記事です。
結論
Elasticsearchにおいて、既存のmappingにあるfieldに対して、multi fieldを追加した場合、documentについて再index(bulk_indexなど)する必要がある。updateではmappingの変更は反映されない。
前提
- Elasticsearch
- seachkick
を使って検索機能を実装しているECサイトを前提とします。
そして、当ECサイトにおいて、商品のデータを格納するindexがあるとして、もともと以下のようなmapping定義があったとします。
{
"mappings": {
"properties": {
"id": {
"type": "integer"
},
}
}
}
そこで、新たに、このid
というfieldに対して、multi fieldを追加して、検索時にはtext
として検索できるようにしたいとなった時には、以下のようなmapping定義を追加します。(multi fieldの追加にはupdate mapping APIが便利です)
これは、id
としてはinteger型で格納するが、id.analyzed
としてはtext型で格納するという定義です。
{
"mappings": {
"properties": {
"id": {
"type": "integer",
"fields": {
"analyzed": {
"type": "text"
}
}
},
}
}
}
起こっていた問題
mapping定義を追加した後、partial reindexを用いて、id
fieldについてのみ、index内の全てのdocumentを更新しようとしました。これは、特定のfieldについてのみ、documentを更新することができる機能です。
class Product < ApplicationRecord
def search_data
{
name: name,
category: category
}.merge(prices_data)
end
def prices_data
{
price: price,
sale_price: sale_price
}
end
end
Product.reindex(:prices_data)
私は、mapping更新後、id
fieldについてのみ、partial reindexを使って、すべてのdocumentを更新すれば、期待通り、検索時にはtext
として検索できるようになると考えていました。しかし、実際には、検索は機能しなかったのです。
なぜpartial reindexではmapping更新後のmapping定義が反映されないのか
これは、partial reindexでは、searchkickの内部実装として、updateが最終的に実行されるためです。
# 例えば、以下のようにして、idについてのみ、partial reindexを実行した場合
Product.reindex(:id)
つまり、partial reindexとはつまり、method_name
を指定して、documentをreindexしていくものであり、method name
があるとき、index.bulk_update
が実行されるということが上からわかります。
では、bulk_updateとbulk_indexの差異
ドキュメントに書いてあるが、updateは、documentの単なる更新を行うものであり、indexは、documentの追加(既にあれば更新し、バージョンをインクリメントする)を行うものである。
- update
-
Updates a document using the specified script.
- https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html#doc_as_upsert
-
- index
-
Adds a JSON document to the specified data stream or index and makes it searchable. If the target is an index and the document already exists, the request updates the document and increments its version.
- https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html
-
mappingを更新した後は、単なるupdateでは、変更前のmappingで更新されてしまう?ようで、変更後のmappingで更新するためには、indexを使う必要があるようです。
Discussion