目次- 1 基本的な集約分析
- 1.1 直接的な集約統計
- 1.2 検索後に集約
- 1.3 拡張: fielddataとkeywordの集約比較
- 2 ネストされた集約
- 2.1 グループ化後に集約統計
- 2.2 グループ化、統計、そしてソート
- 2.3 グループ化、グループ内のグループ化、統計とソート 1 基本的な集約分析 ========
1.1 直接的な集約統計
(1) 各タグのドキュメント数を計算するリクエスト構文:
GET book_shop/it_book/_search
{
"size": 0, // ヒットしたドキュメント情報を表示しない
"aggs": {
"tag_grouping": { // 集約結果の名前、カスタマイズ可能(コメントは削除してください)
"terms": {
"field": "tags"
}
}
}
}
(2) エラーが発生:
説明: 索引book_shopのマッピングはESが自動作成し、タグをtext型として解析しました。タグに対する集約リクエストを送信すると、以下のエラーが発生します:
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [tags] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [......]
},
"status": 400
}
(3) エラー分析:
エラーメッセージ:
Set fielddata=true on [xxxx] ......エラー分析: デフォルトでは、Elasticsearchはtext型のフィールドでfielddataを無効にしています; text型のフィールドはインデックス作成時にトークン化処理が行われますが、集約操作はフィールドの元の値に基づいて分析する必要があります; したがって、text型のフィールドで集約操作を行うには、その元の値を保存する必要があります —— マッピング作成時にfielddata=trueを指定し、倒索インデックスを反転させ(正排インデックス)、インデックスデータをメモリに読み込みます。
(4) 解決策1: text型のフィールドでfielddata属性を有効にする:
- グループ化統計を行うtextフィールド(tags)のfielddataをtrueに設定します:
PUT book_shop/_mapping/it_book
{
"properties": {
"tags": {
"type": "text",
"fielddata": true
}
}
}
- 公式ドキュメントを参照して設定してください: https://www.elastic.co/guide/en/elasticsearch/reference/6.6/fielddata.html. 成功すると以下の結果が得られます:
{
"acknowledged": true
}
- 再度統計すると、以下の結果が得られます:
{
"took": 153,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 0.0,
"hits": []
},
"aggregations": {
"tag_grouping": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 6,
"buckets": [
{
"key": "java",
"doc_count": 3
},
{
"key": "程",
"doc_count": 2
},
......
]
}
}
}
(5) 解決策2: 組み込みのkeywordフィールドを使用する:
- fielddataを有効にすると大量のメモリを消費します。
- Elasticsearch 5.xバージョンから、textの組み込みフィールドkeywordを使用した正確なクエリや集約分析がサポートされています:
GET shop/it_book/_search
{
"size": 0,
"aggs": {
"tag_grouping": {
"terms": {
"field": "tags.keyword" // text型の組み込みkeywordフィールドを使用
}
}
}
}
1.2 検索後に集約
(1) nameに"jvm"を含む図書の各タグのドキュメント数を統計するリクエスト構文:
GET book_shop/it_book/_search
{
"query": {
"match": { "name": "jvm" }
},
"aggs": {
"tag_grouping": { // 集約結果の名前、カスタマイズ可能。以下は組み込みのkeywordフィールドを使用:
"terms": { "field": "tags.keyword" }
}
}
}
(2) レスポンス結果:
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.64072424,
"hits" : [
{
"_index" : "book_shop",
"_type" : "it_book",
"_id" : "2",
"_score" : 0.64072424,
"_source" : {
"name" : "深入理解Java虚拟机:JVM高级特性与最佳实践",
"author" : "周志明",
"category" : "编程语言",
"desc" : "Java图书领域公认的经典著作",
"price" : 79.0,
"date" : "2013-10-01",
"publisher" : "机械工业出版社",
"tags" : [
"Java",
"虚拟机",
"最佳实践"
]
}
}
]
},
"aggregations" : {
"tag_grouping" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 1
},
{
"key" : "最佳实践",
"doc_count" : 1
},
{
"key" : "虚拟机",
"doc_count" : 1
}
]
}
}
}
1.3 拡張: fielddataとkeywordの集約比較
- あるtext型のフィールドでfielddataフィールドを有効にすると、集約分析操作はそのフィールドのすべてのトークンをそれぞれ集約し、得られる結果は多くの場合私たちのニーズに合いません。
- keyword組み込みフィールドを使用すると、関連するトークンの集約は行われず、結果がより有用になる可能性があります。
—— text型フィールドの組み込みkeywordを使用した集約操作をお勧めします。
2 ネストされた集約
2.1 グループ化後に集約統計
(1) まずタグでグループ化し、各タグの図書の平均価格を計算するリクエスト構文:
GET book_shop/it_book/_search
{
"size": 0,
"aggs": {
"tag_grouping": {
"terms": { "field": "tags.keyword" },
"aggs": {
"average_price": {
"avg": { "field": "price" }
}
}
}
}
}
(2) レスポンス結果:
"hits" : {
"total" : 3,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"tag_grouping" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 3,
"average_price" : {
"value" : 102.33333333333333
}
},
{
"key" : "编程语言",
"doc_count" : 2,
"average_price" : {
"value" : 114.0
}
},
......
]
}
}
2.2 グループ化、統計、そしてソート
(1) 各タグの図書の平均価格を計算し、平均価格の降順でソートするクエリ構文:
GET book_shop/it_book/_search
{
"size": 0,
"aggs": {
"all_tags": {
"terms": {
"field": "tags.keyword",
"order": { "average_price": "desc" } // 以下の統計結果に基づいてソート
},
"aggs": {
"average_price": {
"avg": { "field": "price" }
}
}
}
}
}
(2) レスポンス結果:
#2.1節の内容と似ていますが、価格順に表示されている点が異なります。
2.3 グループ化、グループ内のグループ化、統計とソート
(1) まず価格帯でグループ化し、グループ内でタグでグループ化し、各タググループの平均価格を計算するクエリ構文:
GET book_shop/it_book/_search
{
"size": 0,
"aggs": {
"price_grouping": {
"range": {
"field": "price",
"ranges": [
{ "from": 00, "to": 100 },
{ "from": 100, "to": 150 }
]
},
"aggs": {
"tag_grouping": {
"terms": { "field": "tags.keyword" },
"aggs": {
"average_price": {
"avg": { "field": "price" }
}
}
}
}
}
}
}
(2) レスポンス結果:
"hits" : {
"total" : 3,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"price_grouping" : {
"buckets" : [
{
"key" : "0.0-100.0", // 区間0.0-100.0
"from" : 0.0,
"to" : 100.0,
"doc_count" : 1, // 合計3件のドキュメントが見つかりました
"tag_grouping" : { // タグのグループ化集約
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 1,
"average_price" : {
"value" : 79.0
}
},
......
]
}
},
{
"key" : "100.0-150.0",
"from" : 100.0,
"to" : 150.0,
"doc_count" : 2,
"tag_grouping" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Java",
"doc_count" : 2,
"average_price" : {
"value" : 114.0
}
},
......
}
]
}
}
]
}
}