2016-07-08 20 views
2

Angenommen, in einem ES-Index befinden sich Dokumente mit den zwei Feldern user_id und action_id. Wie kann man Benutzer zählen, so dass es Dokumente sowohl unter action_id = 1 als auch unter action_id = 2 gibt?Einen Join in ElasticSearch simulieren

Equivalent SQL wäre

SELECT COUNT(DISTINCT `a`.`uuid`) 
FROM `action` AS `a` 
JOIN `action` AS `b` ON `a`.`user_id` = `b`.`user_id` 
WHERE `a`.`action_id` = 1 
AND `b`.`action_id` = 2 

ich der einzige Weg gefunden, dies zu tun: Anfrage zweimal alle eindeutigen user_id s mit diesen action_id s und finden Durchschnitt von Mengen auf dem ES-Client führt. Dieser Ansatz muss jedoch Megabytes an Daten von ES übertragen, also suche ich nach einer Alternative.

+0

Sie sollten sich wahrscheinlich Eltern-Kind-Beziehung ansehen https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child.html – slawek

+0

@slawek Dies ist statistische Informationen, so dass es hereinkommt ES Reihe für Reihe. Wie ich aus dem Handbuch verstehe, würde die Hinzufügung eines Kindes erfordern, dass der Elternteil und alle Kinder in ES neu erstellt werden. Das sind möglicherweise mehrere Gigabyte Daten. –

+0

Nicht sicher, wo Sie das haben. Von der Seite, die ich verknüpfte: "Untergeordnete Dokumente können hinzugefügt, geändert oder gelöscht werden, ohne dass das übergeordnete oder andere untergeordnete Elemente betroffen sind. Dies ist besonders nützlich, wenn untergeordnete Dokumente zahlreich sind und häufig hinzugefügt oder geändert werden müssen" – slawek

Antwort

3

Sie können es wie folgt tun:

  • erste haben Sie eine Abfrage, die Ihre Dokumente filtert mit Aktionen 1 und 2 nur (Ich habe keine Ahnung, wenn Sie andere Aktionstypen haben können)
  • dann die Magie ist mit Aggregationen
    • die erste Aggregation ist ein terms eine für user_id, so dass Sie einzelne Berechnungen können pro Benutzer
    • dann verwenden Sie eine cardinality Unteraggregation, um die Anzahl der verschiedenen Aktionen pro Benutzer zu zählen. Da die Abfrage für die Aktionen 1 und 2 ist, kann diese Nummer nur 1 oder 2
    • sein, dann verwenden Sie eine bucket_selector Unteraggregation, um nur diejenigen Benutzer zu behalten, die das Kardinalitätsergebnis von 2 haben.
{ 
    "size": 0, 
    "query": { 
    "bool": { 
     "should": [ 
     { 
      "terms": { 
      "action_id": [ 
       1, 
       2 
      ] 
      } 
     } 
     ] 
    } 
    }, 
    "aggs": { 
    "users": { 
     "terms": { 
     "field": "user_id", 
     "size": 10 
     }, 
     "aggs": { 
     "actions": { 
      "cardinality": { 
      "field": "action_id" 
      } 
     }, 
     "actions_count_bucket_filter": { 
      "bucket_selector": { 
      "buckets_path": { 
       "totalActions": "actions" 
      }, 
      "script": "totalActions >= 2" 
      } 
     } 
     } 
    } 
    } 
} 

Das Ergebnis wird wie folgt aussehen:

"aggregations": { 
     "users": { 
     "doc_count_error_upper_bound": 0, 
     "sum_other_doc_count": 0, 
     "buckets": [ 
      { 
       "key": 1, 
       "doc_count": 2, 
       "actions": { 
        "value": 2 
       } 
      }, 
      { 
       "key": 5, 
       "doc_count": 2, 
       "actions": { 
        "value": 2 
       } 
      } 
     ] 
     } 
    } 

Die key s sind die benutzerkennungen deren Handlungen 1und2. bucket_selector Aggregation ist in 2.x + Version von ES verfügbar.

+0

Ich habe das versucht früher würde es in den meisten Fällen funktionieren. Es gibt einige Aggregationen in ES, die über das Ergebnis einer anderen Aggregation laufen könnten, und ich habe versucht, im Ergebnis auf die einzelne Zahl zu kommen (nicht erfolgreich). Dieser Ansatz konnte jedoch aus den Gründen, die ich in der Frage vergessen hatte, nicht funktionieren. Daher musste ich den Schnittpunkt "user_id" verwenden. –

Verwandte Themen