0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

olivereを使ってElastic Searchのネストした集計を実行する

Last updated at Posted at 2022-07-22

はじめに

Go言語のElastic Searchのクライアントを調べると、

の2つが候補になるかと思います。

今回はolivereクライアントを使った、
ネストした集約クエリの実装方法と実行結果の取得方法についてまとめます。

(補足) olivereクライアントは2022/07/23現在Elastic Search v8以降に対応していないので注意してください

実行環境

Go: ver 1.18
Elastic Search: ver 7.17
 

サンプルIndex

サンプルとして以下ようなIndexを想定します

POST users/_bulk 
{ "index" : {} }
{ "name": "user1", "age": 15, "created_at": "2022-07-01" }
{ "index" : {} }
{ "name": "user2", "age": 18, "created_at": "2022-07-01" }
{ "index" : {} }
{ "name": "user3", "age": 22, "created_at": "2022-07-02" }
{ "index" : {} }
{ "name": "user4", "age": 34, "created_at": "2022-07-02" }
{ "index" : {} }
{ "name": "user5", "age": 14, "created_at": "2022-07-03" }
{ "index" : {} }
{ "name": "user6", "age": 40, "created_at": "2022-07-03" }
{ "index" : {} }
{ "name": "user7", "age": 60, "created_at": "2022-07-03" }

集計の設定

実際は検索結果を集計したい場面も多いと思うので、

  • 検索
    • 18歳以上のユーザーで絞り込み
  • 集計

という設定で集計をしてみようと思います

想定クエリ

上記の要件でElastic Searchのクエリを作成すると以下になります

クエリ

GET users/_search?pretty 
{
  "size": 0,
  "query": {
    "range": {
      "age": {
        "gte": 18
      }
    }
  },
  "aggs": {
    "group_by_created_at": {
      "date_histogram": {
        "calendar_interval": "day",
        "field": "created_at"
      },
      "aggs": {
        "average_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  }
}

実行結果

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_created_at" : {
      "buckets" : [
        {
          "key_as_string" : "2022-07-01T00:00:00.000Z",
          "key" : 1656633600000,
          "doc_count" : 1,
          "average_age" : {
            "value" : 18.0
          }
        },
        {
          "key_as_string" : "2022-07-02T00:00:00.000Z",
          "key" : 1656720000000,
          "doc_count" : 2,
          "average_age" : {
            "value" : 28.0
          }
        },
        {
          "key_as_string" : "2022-07-03T00:00:00.000Z",
          "key" : 1656806400000,
          "doc_count" : 2,
          "average_age" : {
            "value" : 50.0
          }
        }
      ]
    }
  }
}

olivereによるクエリ実行

本記事の本題に移ります!

上記のクエリをoliverクライアントを使って記述すると以下になります

package main

import (
	"context"
	"fmt"

	"github.com/olivere/elastic/v7"
)

func main() {
	// See: https://olivere.github.io/elastic/#getting-started
	client, err := elastic.NewClient(
		elastic.SetURL("http://es:9200"),
		elastic.SetBasicAuth("elastic", "password"),
	)

	srv := client.Search("users").Size(0)

	// 1. 検索クエリを定義
	query := elastic.NewRangeQuery("age").Gte(18)
	srv.Query(query)

	// 2. 集約クエリを定義
	agg := elastic.NewDateHistogramAggregation().
		Field("created_at").
		CalendarInterval("day")
	{
		// subクエリを定義
		subAgg := elastic.NewAvgAggregation().Field("age")
		agg.SubAggregation("average_age", subAgg)
	}
	srv.Aggregation("group_by_created_at", agg)

	// 3. 実行
	ctx := context.Background()
	result, err := srv.Pretty(true).Do(ctx)
	if err != nil {
		panic(err)
	}

	// 4. 集約結果を取得
	dateHistItems, found := result.Aggregations.DateHistogram("group_by_created_at")
	if !found {
		panic("not found")
	}
	for _, bucket := range dateHistItems.Buckets {
		fmt.Println("--- date ---")
		fmt.Println(*bucket.KeyAsString)

		avgResult, found := bucket.Aggregations.Avg("average_age")
		if !found {
			panic("not found")
		}
		fmt.Println("--- average age ---")
		fmt.Println(*avgResult.Value)
		fmt.Println()
	}
}

実行結果

--- date ---
2022-07-01T00:00:00.000Z
--- average age ---
18

--- date ---
2022-07-02T00:00:00.000Z
--- average age ---
28

--- date ---
2022-07-03T00:00:00.000Z
--- average age ---
50

おわりに

olivereはメソッドチェーンのように記述でき、慣れてくると直感的に実装出来るようになるのでおすすめです。

ただし、複雑な集計をした実行結果を取得する方法に関するの記事が少なかったので、

少しでも役に立てば幸いです。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?