使用python在elasticsearch-dsl中聚合一个字段

时间:2015-03-31 23:19:23

标签: python elasticsearch elasticsearch-dsl

有人能告诉我如何编写Python语句来汇总(总结和计算)有关我文档的内容吗?


SCRIPT

from datetime import datetime
from elasticsearch_dsl import DocType, String, Date, Integer
from elasticsearch_dsl.connections import connections

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search, Q

# Define a default Elasticsearch client
client = connections.create_connection(hosts=['http://blahblahblah:9200'])

s = Search(using=client, index="attendance")
s = s.execute()

for tag in s.aggregations.per_tag.buckets:
    print (tag.key)

输出

File "/Library/Python/2.7/site-packages/elasticsearch_dsl/utils.py", line 106, in __getattr__
'%r object has no attribute %r' % (self.__class__.__name__, attr_name))
AttributeError: 'Response' object has no attribute 'aggregations'

造成这种情况的原因是什么? “聚合”关键字是错误的吗?我需要导入一些其他包吗?如果“出勤”索引中的文档有一个名为emailAddress的字段,我如何计算哪些文档具有该字段的值?

2 个答案:

答案 0 :(得分:25)

首先。我现在注意到我在这里写的,实际上没有定义聚合。关于如何使用它的文档对我来说不是很易读。用我上面写的,我会扩展。我正在更改索引名称以获得更好的示例。

from datetime import datetime
from elasticsearch_dsl import DocType, String, Date, Integer
from elasticsearch_dsl.connections import connections

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search, Q

# Define a default Elasticsearch client
client = connections.create_connection(hosts=['http://blahblahblah:9200'])

s = Search(using=client, index="airbnb", doc_type="sleep_overs")
s = s.execute()

# invalid! You haven't defined an aggregation.
#for tag in s.aggregations.per_tag.buckets:
#    print (tag.key)

# Lets make an aggregation
# 'by_house' is a name you choose, 'terms' is a keyword for the type of aggregator
# 'field' is also a keyword, and 'house_number' is a field in our ES index
s.aggs.bucket('by_house', 'terms', field='house_number', size=0)

上面我们为每个门牌号创建一个桶。因此,桶的名称将是门牌号。 ElasticSearch(ES)将始终提供适合该存储桶的文档的文档计数。 Size = 0表示使用所有结果,因为ES有一个默认设置只能返回10个结果(或者你的dev设置它做什么)。

# This runs the query.
s = s.execute()

# let's see what's in our results

print s.aggregations.by_house.doc_count
print s.hits.total
print s.aggregations.by_house.buckets

for item in s.aggregations.by_house.buckets:
    print item.doc_count

我之前的错误是认为弹性搜索查询默认具有聚合。您可以自己定义它们,然后执行它们。然后您的回复可以与您提到的聚合器分开。

上述的CURL应如下所示:
注意:我为Google Chrome使用SENSE ElasticSearch插件/扩展程序/插件。在SENSE中,您可以使用//来评论内容。

POST /airbnb/sleep_overs/_search
{
// the size 0 here actually means to not return any hits, just the aggregation part of the result
    "size": 0,
    "aggs": {
        "by_house": {
            "terms": {
// the size 0 here means to return all results, not just the the default 10 results
                "field": "house_number",
                "size": 0
            }
        }
    }
}

工作-周围。 DSL的GIT上有人告诉我忘记翻译,只是使用这种方法。它更简单,你可以在CURL中编写棘手的东西。这就是我称之为解决方案的原因。

# Define a default Elasticsearch client
client = connections.create_connection(hosts=['http://blahblahblah:9200'])
s = Search(using=client, index="airbnb", doc_type="sleep_overs")

# how simple we just past CURL code here
body = {
    "size": 0,
    "aggs": {
        "by_house": {
            "terms": {
                "field": "house_number",
                "size": 0
            }
        }
    }
}

s = Search.from_dict(body)
s = s.index("airbnb")
s = s.doc_type("sleepovers")
body = s.to_dict()

t = s.execute()

for item in t.aggregations.by_house.buckets:
# item.key will the house number
    print item.key, item.doc_count

希望这会有所帮助。我现在在CURL中设计所有内容,然后使用Python语句剥离结果以获得我想要的内容。这有助于进行多级聚合(子聚合)。

答案 1 :(得分:1)

我还没有评论的代表,但是想对Matthew对VISQL关于from_dict的答案的评论做一个小修正。如果要维护搜索属性,请使用update_from_dict而不是from_dict。

根据Docs,from_dict将创建一个新的搜索对象,但是update_from_dict将在适当的位置进行修改,如果Search已经具有诸如索引,使用等属性,这就是您想要的

因此,您需要在搜索之前声明查询主体,然后像这样创建搜索:

query_body = {
    "size": 0,
    "aggs": {
        "by_house": {
            "terms": {
                "field": "house_number",
                "size": 0
            }
        }
    }
}

s = Search(using=client, index="airbnb", doc_type="sleep_overs").update_from_dict(query_body)