Elasticsearchで特定のフィールドのすべての一意の値を検索するにはどうすればよいですか?
select full_name from authors
のような種類のクエリがあるので、フォームのリストをユーザーに表示できます。
「full_name」フィールドに terms facet を作成できます。しかし、それを適切に行うには、インデックス作成中にトークン化しないことを確認する必要があります。そうしないと、ファセット内のすべてのエントリは、フィールドコンテンツの一部である異なる用語になります。ほとんどの場合、マッピングで「not_analyzed」として設定する必要があります。それも検索しているのにトークン化したい場合は、 multi field を使用して2つの異なる方法でインデックスを付けることができます。
また、full_nameフィールドの一部である一意の用語の数に応じて、この操作はコストがかかり、かなりのメモリを必要とすることを考慮する必要があります。
Elasticsearch 1.0以降では、terms aggregation
これをする、
クエリDSL:
{
"aggs": {
"NAME": {
"terms": {
"field": "",
"size": 10
}
}
}
}
実際の例:
{
"aggs": {
"full_name": {
"terms": {
"field": "authors",
"size": 0
}
}
}
}
その後、authors
フィールドのすべての一意の値を取得できます。 size = 0は、用語の数を制限しないことを意味します(これにはesが1.1.0以降である必要があります)。
応答:
{
...
"aggregations" : {
"full_name" : {
"buckets" : [
{
"key" : "Ken",
"doc_count" : 10
},
{
"key" : "Jim Gray",
"doc_count" : 10
},
]
}
}
}
Elasticsearch Terms Aggregations を参照してください。
次の理由により、Elasticsearch 5.Xでは既存の回答が機能しませんでした。
"size": 0
_は、「[サイズ]は0より大きくなければならない」ため、解析に失敗しました。full_name
_フィールドを検索できないことを意味します。ただし、分析には未分析のkeyword
フィールドを使用できます。ソリューション1: Scroll API を使用します。検索コンテキストを保持し、結果の後続のバッチを返すたびに複数の要求を行うことで機能します。 Pythonを使用している場合、elasticsearchモジュールには scan()
ヘルパー関数 があり、スクロールを処理してすべての結果を返します。
ソリューション2: Search After API を使用します。スクロールに似ていますが、検索コンテキストを保持する代わりにライブカーソルを提供します。したがって、リアルタイムリクエストの方が効率的です。
直観: SQLの用語では:
Select distinct full_name from authors;
に等しい
Select full_name from authors group by full_name;
そのため、ElasticSearchのグループ化/集計構文を使用して、個別のエントリを見つけることができます。
以下がエラスティック検索に格納されている構造であると仮定します。
[{
"author": "Brian Kernighan"
},
{
"author": "Charles Dickens"
}]
機能しなかったもの:単純な集約
{
"aggs": {
"full_name": {
"terms": {
"field": "author"
}
}
}
}
次のエラーが表示されました:
{
"error": {
"root_cause": [
{
"reason": "Fielddata is disabled on text fields by default...",
"type": "illegal_argument_exception"
}
]
}
}
チャームのように機能したもの:追加。keywordフィールドで
{
"aggs": {
"full_name": {
"terms": {
"field": "author.keyword"
}
}
}
}
そして、サンプル出力は次のようになります:
{
"aggregations": {
"full_name": {
"buckets": [
{
"doc_count": 372,
"key": "Charles Dickens"
},
{
"doc_count": 283,
"key": "Brian Kernighan"
}
],
"doc_count": 1000
}
}
}
ボーナスチップ:
問題のフィールドが次のようにネストされていると仮定します。
[{
"authors": [{
"details": [{
"name": "Brian Kernighan"
}]
}]
},
{
"authors": [{
"details": [{
"name": "Charles Dickens"
}]
}]
}
]
正しいクエリは次のようになります。
{
"aggregations": {
"full_name": {
"aggregations": {
"author_details": {
"terms": {
"field": "authors.details.name"
}
}
},
"nested": {
"path": "authors.details"
}
}
},
"size": 0
}
Elasticsearch 5.2.2での作業
curl -XGET http://localhost:9200/articles/_search?pretty -d '
{
"aggs" : {
"whatever" : {
"terms" : { "field" : "yourfield", "size":10000 }
}
},
"size" : 0
}'
"size":10000
は、最大で10000個の一意の値を取得することを意味します。これがないと、10を超える一意の値がある場合、10の値のみが返されます。
"size":0
は、結果として"hits"
にはドキュメントが含まれません。デフォルトでは、10個のドキュメントが返されますが、これは必要ありません。
参照: バケット用語の集計
また、 このページ によると、ファセットはElasticsearch 1.0の集約に置き換えられています。これはファセットのスーパーセットです。