目次
この記事はElastic Stack (Elasticsearch) Advent Calendar 2025の19日目の記事になります。
なんとなく思い立ったので、Named Queryのことでも書いてみようかな。
named queryとは?
ElasticsearchのBoolクエリを書いていて、条件が複数ある場合にどの条件が検索結果に出てきたドキュメントに影響があるのか?というのを知りたくなることがあります。
例えば、タイトルと説明文に検索するようなBoolクエリを書いてみます。
GET esci-sample/_search
{
"query": {
"bool": {
"should":[
{
"match": {
"product_title": "ライトニングケーブル"
}
},
{
"match": {
"product_description": "ライトニングケーブル"
}
}
]
}
},
"_source": ["product_title"]
}
取得できるのはこういうデータです(説明文は長いので省いています)。 ヒットしているデータはわかりますが、どっちの条件がヒットしてるのか?というのはスコアから想像するとわかるような気もしますが、難しいです。
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 3.4320617,
"hits": [
{
"_index": "esci-sample",
"_id": "B07RJQJDY1",
"_score": 3.4320617,
"_source": {
"product_title": "ライトニングケーブル Type-Cケーブル Micro USB ケーブル 3in1 充電ケーブル 3A急速充電 データ転送 高耐久編組ナイロン USB Type C/ライトニング/Micro USB iOS / Androidに多機種対応1.2m (ブラック)"
}
},
{
"_index": "esci-sample",
"_id": "B086HNZN58",
"_score": 2.949997,
"_ignored": [
"product_bullet_point.keyword"
],
"_source": {
"product_title": "Allroundo® ライトニングケーブル 伸縮式 3in1 充電ケーブル 1.8A急速充電 高速データ転送 USB Type-C/Lightning/MicroUSB 多機種対応 高耐久 断線防止 絡み防止 持ち運びに便利 収納ボックス付き"
}
},
{
"_index": "esci-sample",
"_id": "B0829TWWMM",
"_score": 2.697413,
"_ignored": [
"product_bullet_point.keyword"
],
"_source": {
"product_title": "ライトニングケーブル 3in1 巻き取り 充電ケーブル 3in1 3A 急速充電 高速データ転送(ios) USB Type-C/ライトニング/Micro USB 充電ケーブル 一本三役 iOS/Android 同時給電可能 iPhone/Galaxy/Huawei/Macbook等全機種対応 120cm 1年間品質保証 (ブラック)"
}
},
{
"_index": "esci-sample",
"_id": "B08913D1SL",
"_score": 2.5449233,
"_ignored": [
"product_bullet_point.keyword",
"product_description.keyword"
],
"_source": {
"product_title": "【Quick Charge 3.0】Amuvec 車載充電器 USB2ポートカーチャージャー シガーソケットチャージャ しがらいたーソケット usb 急速充電(6A/40W) LightningとタイプCデュアル80cm 巻取り式ケーブル ために iPhone XS/ Max/ XR/ X/ 8 /7/ 6/ Plus /Galaxy S9/ S8/ Note 8 LG V30 Google Pixel 2 XL/SamSung 対応 (赤) …"
}
}
]
}
}
そういう時に便利な機能としてNamed Queryと呼ばれるものがあります。
クエリに名前を付けることができる機能で、さらにその名前が検索結果に帰ってくるようになります。
GET esci-sample/_search
{
"query": {
"bool": {
"should":[
{
"match": {
"product_title": {
"query": "ライトニングケーブル",
"_name": "match_title"
}
}
},
{
"match": {
"product_description": {
"query": "ライトニングケーブル",
"_name": "match_description"
}
}
}
]
}
},
"_source": false
}
matchのクエリの書き方が少し変わっていて、フィールド名のあとがオブジェクトになっています(_nameもこの中に指定するため)。
この中に、_nameというのがNamed Queryになります。
クエリの結果が次のようになります(titleが長いので、省いちゃいます)。
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 3.4320617,
"hits": [
{
"_index": "esci-sample",
"_id": "B07RJQJDY1",
"_score": 3.4320617,
"matched_queries": [
"match_title"
]
},
{
"_index": "esci-sample",
"_id": "B086HNZN58",
"_score": 2.949997,
"_ignored": [
"product_bullet_point.keyword"
],
"matched_queries": [
"match_title"
]
},
{
"_index": "esci-sample",
"_id": "B0829TWWMM",
"_score": 2.697413,
"_ignored": [
"product_bullet_point.keyword"
],
"matched_queries": [
"match_title"
]
},
{
"_index": "esci-sample",
"_id": "B08913D1SL",
"_score": 2.5449233,
"_ignored": [
"product_bullet_point.keyword",
"product_description.keyword"
],
"matched_queries": [
"match_description"
]
}
]
}
}
結果を見ていただくと、各ドキュメントにmatched_queriesという属性が増えています。
ここに、ヒットしたクエリの名前が入るようになります。
今回の検索結果の場合、3件目まではタイトルにヒットしていますが、4件目は説明文にヒットしていることがわかります。
じゃあ、スコアは?
ここまではどの条件が検索結果に関係があったかどうか?だけがわかる仕組みでした。
Elasticsearchの8.8から更なるオプションとしてinclude_named_queries_scoreが追加されました(追加の時のPRはこちら)。
_searchエンドポイントのクエリパラメータとして(URLの一部)指定します
(効果をわかりやすくするために、上記のクエリとは文字列を変えています)。
GET esci-sample/_search?include_named_queries_score=true
{
"query": {
"bool": {
"should":[
{
"match": {
"product_title": {
"query": "USBケーブル",
"_name": "match_title"
}
}
},
{
"match": {
"product_description": {
"query": "USBケーブル",
"_name": "match_description"
}
}
}
]
}
},
"_source": false
}
検索結果は次のようになります。
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 19,
"relation": "eq"
},
"max_score": 16.192907,
"hits": [
{
"_index": "esci-sample",
"_id": "B07ZNCJB3B",
"_score": 16.192907,
"_ignored": [
"product_bullet_point.keyword"
],
"matched_queries": {
"match_description": 8.697643,
"match_title": 7.495263
}
},
{
"_index": "esci-sample",
"_id": "B07SG28ZS8",
"_score": 12.9889765,
"_ignored": [
"product_bullet_point.keyword"
],
"matched_queries": {
"match_description": 4.4317617,
"match_title": 8.557215
}
},
単なるNamed Queryの時はmatched_queriesの部分はクエリの名前がリストで返ってきていました。
が、今回はオブジェクトに変わっており、クエリの名前に対してそのクエリのスコアが返ってくるようになっています。
explainパラメータを使って、スコアの内訳をみることもできますがレスポンスが肥大化してしまいますし、見るのがつらいことが多いです。
簡易的に、どの条件がどのくらいスコアとして寄与しているのか?を見るためにはこちらのオプションを利用するのが便利でしょう。
まとめ
ElasticsearchのNamed Queryがどんなものなのか?と8.8から追加されたinclude_named_queries_scoreパラメータについて簡単に紹介しました。
Elasticsearchでの検索結果改善の参考になればと。
comments powered by Disqus
See Also by Hugo
- validate APIの利用
- elasticsearch-inquisitorプラグインの紹介
- Weaviateを使って個人的備忘録を作ってる
- ElasticsearchのRetrieverについて調べたので雑にメモ
- Querqyの調査(その1)