使用elasticsearch-dsl编写带有聚合的搜索查询
我尝试使用 Elasticsearch 的高级 Python 客户端 elasticsearch-dsl(文档)进行操作。使用 elasticsearch-dsl,相比于使用低级 Python 客户端 elasticsearch,可以更直观地创建搜索查询。
前期准备
首先,将创建以下类似的索引数据。
from elasticsearch import Elasticsearch
elastic = Elasticsearch()
index = "dsl_sample"
elastic.indices.create(index)
data = [
{"hoge": 1, "fuga": 1, "value": 3},
{"hoge": 1, "fuga": 2, "value": 4},
{"hoge": 2, "fuga": 1, "value": 5},
{"hoge": 2, "fuga": 2, "value": 6},
{"hoge": 1, "fuga": 1, "value": 100}
]
for i, body in enumerate(data, 1):
elastic.index(index=index, doc_type="_doc", id=i, body=body)
进行搜索和统计
这次我将创建以下类型的查询请求来进行汇总。
-
- valueが1以上100未満の値のみが集計対象となるようにフィルタする
- 1つのクエリで「hoge で Groub By した集計結果」と「fuga で Group By した集計結果」の2つを取得する
您可以使用elasticsearch-dsl来执行以下查询。
from elasticsearch_dsl import Search, A
search = Search(using=elastic, index=index) # ① Search オブジェクトの作成
search = search.filter("range", value={"gte": 1, "lt": 100}) # ②フィルタ条件の記載
search = search.extra(size=0) # ③ドキュメントの取得件数を指定
# ④ Aggregation オブジェクトの作成
aggs_hoge = A("terms", field="hoge", size=10).metric('sum_value', 'sum', field='value')
aggs_fuga = A("terms", field="fuga", size=10).metric('sum_value', 'sum', field='value')
# ⑤ Aggregation オブジェクトを Search オブジェクトに紐付ける
search.aggs.bucket("aggs_name_hoge", aggs_hoge)
search.aggs.bucket("aggs_name_fuga", aggs_fuga)
response = search.execute()
-
- ①で検索に用いるオブジェクトを作成します。例のように using で既に作成した低レベルクライアントを渡すことも可能ですし、 connections を用いて接続することもできるようです。
-
- 今回は集計結果が取得できればよく、ドキュメント自体を返却する必要はないので③で取得件数を 0 に指定しています。extraを用いれば検索リクエストに任意のプロパティ値を設定できるようです。
-
- ④の A で集計について定義しています。
A の field で集計のキーを指定しています。
metric を用いて、どのカラムをどのように集計するのかを指定します。なおドキュメント数のみで良い場合は metric の指定が不要となります。
⑤で検索オブジェクトに集計オブジェクトを関連づけます。このように2回 bucket を呼ぶことで、2種類の集計が関連づけられます。
为了解释,我在这里分成几行,但在①〜③之间,像Search(・・・).filter(・・・).extra(・・・)这样的方法链可以直观地编写,这很好啊。
对于结果,可以按照以下方式进行访问。
response.aggregations.aggs_name_hoge.buckets
# [{'key': 1, 'doc_count': 2, 'sum_value': {'value': 7.0}}, {'key': 2, 'doc_count': 2, 'sum_value': {'value': 11.0}}]
response.aggregations.aggs_name_fuga.buckets
# [{'key': 1, 'doc_count': 2, 'sum_value': {'value': 8.0}}, {'key': 2, 'doc_count': 2, 'sum_value': {'value': 10.0}}]
我可以看出数据已经被正确汇总。
确认查询字典
在elasticsearch-dsl中,您可以使用to_dict方法来获取在低级客户端中发送请求时的搜索查询字典。
search.to_dict()
# {
# 'query': {
# 'bool': {
# 'filter': [
# {
# 'range': {
# 'value': {
# 'gte': 1,
# 'lt': 100
# }
# }
# }
# ]
# }
# },
# 'aggs': {
# 'aggs_name_hoge': {
# 'terms': {
# 'field': 'hoge',
# 'size': 10
# },
# 'aggs': {
# 'sum_value': {
# 'sum': {
# 'field': 'value'
# }
# }
# }
# },
# 'aggs_name_fuga': {
# 'terms': {
# 'field': 'fuga',
# 'size': 10
# },
# 'aggs': {
# 'sum_value': {
# 'sum': {
# 'field': 'value'
# }
# }
# }
# }
# },
# 'size': 0
# }
如果要使用低级别的Python客户端elasticsearch来创建搜索查询,那么需要直接创建这个字典,相比之下,使用elasticsearch-dsl可以更轻松地编写搜索查询。
最后
这次我尝试使用elasticsearch-dsl编写了一个简单的聚合查询。
起初对于”如何设置两个聚合?”或者”如何指定size=0?”这样的问题有些摸索,但一旦熟悉了,就能够像django的QuerySet一样使用方法链来编写搜索查询,觉得直观而好用。
明天@usangit将会写些什么。期待吧!