2015-03-31 15 views
6

Qualcuno può dirmi come scrivere istruzioni Python che aggregheranno (sommano e contano) cose sui miei documenti?aggregare un campo in elasticsearch-dsl usando 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) 

USCITA

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' 

cosa sta causando questo? La parola chiave "aggregazioni" è sbagliata? C'è qualche altro pacchetto che devo importare? Se un documento nell'indice "presenze" ha un campo chiamato emailAddress, come potrei contare quali documenti hanno un valore per quel campo?

+1

Posso chiederti se sei riuscito a rispondere alle tue domande oppure no? Sto affrontando esattamente gli stessi problemi ora - non so come fare l'aggregazione dei conteggi in elasticsearch-dsl – Jacobian

+0

Sì. Da allora ho ostacolato alcuni ostacoli. Con l'aiuto dei programmatori di dsl, sto usando quello che considero un work-around per farlo in Python. Sfortunatamente, non ho avuto il tempo di usare questo modo puramente DSL, ma invece ho utilizzato to_dict. Proverò a incollare un buon esempio. – VISQL

risposta

16

Prima di tutto. Ora noto che ciò che ho scritto qui, in realtà, non ha definito alcuna aggregazione. La documentazione su come usare questo non è molto leggibile per me. Usando quello che ho scritto sopra, mi espanderò. Sto cambiando il nome dell'indice per fare un esempio migliore.

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) 

Sopra stiamo creando 1 secchio per numero civico. Pertanto, il nome del bucket sarà il numero civico. ElasticSearch (ES) fornirà sempre un conteggio documenti dei documenti che si adattano a quel bucket. Size = 0 significa dare tutti i risultati, dato che ES ha un'impostazione predefinita per restituire solo 10 risultati (o qualsiasi cosa il tuo dev lo abbia impostato per fare).

# 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 

L'errore precedente era pensare che una query di ricerca elastica avesse aggregazioni per impostazione predefinita. Li definisci tu stesso, poi li esegui. Quindi la tua risposta può essere divisa dagli aggregatori che hai citato.

Il CURL per quanto sopra deve avere il seguente aspetto:
NOTA: uso SENSE un plug-in/estensione/add-on ElasticSearch per Google Chrome. In SENSE puoi usare // per commentare le cose.

In giro. Qualcuno al GIT di DSL mi ha detto di dimenticare la traduzione e di usare solo questo metodo. È più semplice e puoi scrivere le cose difficili in CURL. Ecco perché lo chiamo un work-around.

# 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 

Spero che questo aiuti. Ora disegno tutto in CURL, quindi uso l'istruzione Python per staccare i risultati per ottenere ciò che voglio. Ciò aiuta le aggregazioni con più livelli (sotto-aggregazioni).

+0

Grazie, VISQL! Trovo la tua risposta molto istruttiva e utile! – Jacobian