集計結果を効率的に除外/検索するにはどうすればよいですか?
ElasticSearchに100万のドキュメントがあると想像してください。これらのドキュメントには、multi_field(キーワード、テキスト)がありtags
ます。
{
...
tags: ['Race', 'Racing', 'Mountain Bike', 'Horizontal'],
...
},
{
...
tags: ['Tracey Chapman', 'Silverfish', 'Blue'],
...
},
{
...
tags: ['Surfing', 'Race', 'Disgrace'],
...
},
これらの値をクエリに対するフィルター(ファセット)として使用して、このタグを含むドキュメントのみをプルできます。
...
"filter": [
{
"terms": {
"tags": [
"Race"
]
}
},
...
]
ただし、ユーザーが可能なタグフィルターを照会できるようにする必要があります。したがって、ユーザーが入力するとrace
、(前の例の)戻り値が表示され['Race', 'Tracey Chapman', 'Disgrace']
ます。このようにして、ユーザーは使用するフィルターを照会できます。これを実現するには、集計を使用する必要がありました。
{
"aggs": {
"topics": {
"terms": {
"field": "tags",
"include": ".*[Rr][Aa][Cc][Ee].*", // I have to dynamically form this
"size": 6
}
}
},
"size": 0
}
これは私に必要なものを正確に与えてくれます!しかし、それは遅いです、非常に遅いです。execute_hintを追加しようとしましたが、役に立ちません。
「集計の前にクエリを使用するだけです!」と思うかもしれません。ただし、問題は、そのクエリ内のすべてのドキュメントのすべての値を取得することです。つまり、まったく関係のないタグを表示することができます。race
集計の前にクエリを実行し、include正規表現を使用しなかった場合、次のような他のすべての値になります。'Horizontal', etc...
この集計を書き換えてより高速に動作させるにはどうすればよいですか?これを書くためのより良い方法はありますか?値のためだけに別のインデックスを作成する必要がありますか?(悲しい顔)これは一般的な問題のようですが、ドキュメントやグーグルで答えが見つかりませんでした。
値のためだけに個別のインデックスは必要ありません...
これが私の見解です:
Race
をn-gramにトークン化する必要があることを意味し["rac", "race", "ace"]
ます。(3文字未満にすることは実際には意味がありません。ほとんどのオートコンプリートライブラリは、一致する可能性のあるバルーンが速すぎるため、3文字未満を無視することを選択します。)ElasticsearchはN-grammax_ngram_diff
トークナイザーを提供しますが、妥当な数のngramをキャッチしたいので、呼び出されるデフォルトのインデックスレベル設定を1から(任意に)10に増やす必要があります。
PUT tagindex
{
"settings": {
"index": {
"max_ngram_diff": 10
},
"analysis": {
"analyzer": {
"my_ngrams_analyzer": {
"tokenizer": "my_ngrams",
"filter": [ "lowercase" ]
}
},
"tokenizer": {
"my_ngrams": {
"type": "ngram",
"min_gram": 3,
"max_gram": 10,
"token_chars": [ "letter", "digit" ]
}
}
}
},
{ "mappings": ... } --> see below
}
tags
、フィールドがキーワードのリストである、それはその場に集約するだけではできませんせずに頼らinclude
完全一致または(あなたがすでに使用している)正規表現のいずれかになりますオプション。現在、完全一致を保証することはできませんが、正規表現もしたくありません。それでは、なぜ私たちが使用する必要があることを、ネストされたリストwhich'll個別に各タグの治療を。現在、ネストされたリストにはオブジェクトが含まれていると予想されるため、
{
"tags": ["Race", "Racing", "Mountain Bike", "Horizontal"]
}
に変換する必要があります
{
"tags": [
{ "tag": "Race" },
{ "tag": "Racing" },
{ "tag": "Mountain Bike" },
{ "tag": "Horizontal" }
]
}
その後、元のタグをそのまま維持しながら、検索するフィールドと集計するフィールドを追加して、マルチフィールドマッピングを続行します。.tokenized
.keyword
"index": { ... },
"analysis": { ... },
"mappings": {
"properties": {
"tags": {
"type": "nested",
"properties": {
"tag": {
"type": "text",
"fields": {
"tokenized": {
"type": "text",
"analyzer": "my_ngrams_analyzer"
},
"keyword": {
"type": "keyword"
}
}
}
}
}
}
}
次に、調整したタグのドキュメントを追加します。
POST tagindex/_doc
{"tags":[{"tag":"Race"},{"tag":"Racing"},{"tag":"Mountain Bike"},{"tag":"Horizontal"}]}
POST tagindex/_doc
{"tags":[{"tag":"Tracey Chapman"},{"tag":"Silverfish"},{"tag":"Blue"}]}
POST tagindex/_doc
{"tags":[{"tag":"Surfing"},{"tag":"Race"},{"tag":"Disgrace"}]}
GET tagindex/_search
{
"aggs": {
"topics_parent": {
"nested": {
"path": "tags"
},
"aggs": {
"topics": {
"filter": {
"term": {
"tags.tag.tokenized": "race"
}
},
"aggs": {
"topics": {
"terms": {
"field": "tags.tag.keyword",
"size": 100
}
}
}
}
}
}
},
"size": 0
}
降伏
{
...
"topics_parent" : {
...
"topics" : {
...
"topics" : {
...
"buckets" : [
{
"key" : "Race",
"doc_count" : 2
},
{
"key" : "Disgrace",
"doc_count" : 1
},
{
"key" : "Tracey Chapman",
"doc_count" : 1
}
]
}
}
}
}
警告
PS:これは興味深いユースケースです。実装がどのように進んだか教えてください!
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加