web-dev-qa-db-ja.com

Elasticsearchを使用してフィールドのすべての一意の値をクエリする

Elasticsearchで特定のフィールドのすべての一意の値を検索するにはどうすればよいですか?

select full_name from authorsのような種類のクエリがあるので、フォームのリストをユーザーに表示できます。

30
kiran

「full_name」フィールドに terms facet を作成できます。しかし、それを適切に行うには、インデックス作成中にトークン化しないことを確認する必要があります。そうしないと、ファセット内のすべてのエントリは、フィールドコンテンツの一部である異なる用語になります。ほとんどの場合、マッピングで「not_analyzed」として設定する必要があります。それも検索しているのにトークン化したい場合は、 multi field を使用して2つの異なる方法でインデックスを付けることができます。

また、full_nameフィールドの一部である一意の用語の数に応じて、この操作はコストがかかり、かなりのメモリを必要とすることを考慮する必要があります。

18
javanna

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 を参照してください。

12
Gary Gauh

次の理由により、Elasticsearch 5.Xでは既存の回答が機能しませんでした。

ソリューション1Scroll API を使用します。検索コンテキストを保持し、結果の後続のバッチを返すたびに複数の要求を行うことで機能します。 Pythonを使用している場合、elasticsearchモジュールには scan()ヘルパー関数 があり、スクロールを処理してすべての結果を返します。

ソリューション2Search After API を使用します。スクロールに似ていますが、検索コンテキストを保持する代わりにライブカーソルを提供します。したがって、リアルタイムリクエストの方が効率的です。

4

直観: 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
}
2

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の集約に置き換えられています。これはファセットのスーパーセットです。

2
sam