Elasticsearchによる集約検索の実装(グループ化統計)

目次- 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
        }
    }
}
{
  "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
                }
              },
              ......
              }
            ]
          }
        }
      ]
    }
  }

タグ: Elasticsearch 集約検索 グループ化統計 fielddata keyword

7月20日 23:10 投稿