2016-03-17 4 views
7

Stellen Sie sich vor, dass ich einen Besuch Index haben, der Dokumente des Typs ‚Besuch‘ enthält, die wie folgt aussehen:Wie kann ich meine Daten umformen, bevor ich sie in ein Histogramm umwandele?

{ 
       "id": "c223a991-b4e7-4333-ba45-a576010b568b", 
// other properties 
       "buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e", 
       "arrivalDateTimeUtc": "2015-12-22T21:15:00Z" 
} 

Die folgende Funktion wird ein Histogramm zurück, die im angegebenen Bereich für jeden Tag Eimer Besuche kehrt nach zur angegebenen Zeitzone.

public Bucket<HistogramItem> Execute(MyParameterType parameters) 
    { 
     var buildingFilter = Filter<VisitProjection>.Term(x => x.BuildingId, parameters.BuildingId); 
     var dateFilter = Filter<VisitProjection>.Range(r => r 
      .OnField(p => p.ArrivalDateTimeUtc) 
      .GreaterOrEquals(parameters.EarliestArrivalDateTimeUtc) 
      .LowerOrEquals(parameters.LatestArrivalDateTimeUtc) 
     ); 

     var result = _elasticClient.Search<VisitProjection>(s => s 
      .Index("visits") 
      .Type("visit") 
      .Aggregations(a => a 
       .Filter("my_filter_agg", f => f 
        .Filter(fd => buildingFilter && dateFilter) 
         .Aggregations(ta => ta.DateHistogram("my_date_histogram", h => h 
          .Field(p => p.ArrivalDateTimeUtc) 
          .Interval(parameters.DateInterval) // "day" 
          .TimeZone(NodaTimeHelpers.WindowsToIana(parameters.TimeZoneInfo)) // This is a critical piece of the equation. 
          .MinimumDocumentCount(0) 
         ) 
        ) 
       ) 
      ) 
     ); 

     return result.Aggs.Nested("my_filter_agg").DateHistogram("my_date_histogram"); 
    } 
} 

// Returns [{Date: 12/22/2015 12:00:00 AM, DocCount: 1}] 

Nun stell dir vor, dass ich die Dinge ein wenig verändert werden. Stellen Sie sich vor, dass ich ein neues Feld in dem Dokument hinzugefügt:

{ 
       "id": "c223a991-b4e7-4333-ba45-a576010b568b", 
// other properties 
       "buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e", 
       "arrivalDateTimeUtc": "2015-12-22T21:15:00Z", 
       "departureDateTimeUtc": "2015-12-23T22:00:00Z" // new property 
} 

Und davon ausgehen, dass ich folgendes zurückkehren wollen:

// Returns [{Date: 12/22/2015 12:00:00 AM, DocCount: 1}, {Date: 12/23/2015 12:00:00 AM, DocCount: 1}] 

weil der Besuch überspannte zwei Tage und ich will ein Datum Histogramm, das eine aufzeichnet Einheit für jeden Tag, den ein Besuch überspannt.

Wie würde ich das mit NEST/Elastic Search machen?


Anmerkung 1: Es sei denn, jemand kann mir sonst überzeugt, ich glaube nicht eine gute Idee wäre, alle Dokumente im Bereich zu sammeln und die Aggregation/bucketization und Datum Histogramm in der mittleren Ebene (oder C# ausführen Schicht).

Hinweis 2: Der Zeitzonenaspekt dieses Problems ist kritisch, da ich die Anzahl der zu definierenden Zeitzonen benötigen.

Antwort

4

Ein Weg könnte sein, die scripted_metric aggregation zu verwenden und das Bucketing selbst basierend auf Ihren zwei Datumsfeldern durchzuführen. Ziemlich verworren und nicht wirklich performant, abhängig davon, wie viele Dokumente Sie haben.

könnte jedoch eine andere einfachere Lösung sein, ein einziges Datumsfeld zu verwenden und setzen alle Termine des Intervalls in ein Array (Ankunft erste Abfahrt letzte und alle anderen Termine dazwischen), wie folgt aus:

{ 
    "id": "c223a991-b4e7-4333-ba45-a576010b568b", 
    "buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e", 
    "visitDateTimeUtc": ["2015-12-22T21:15:00Z", "2015-12-23T22:00:00Z" ] 
} 

und wenn ein Besuch drei/vier/etc Tage erstreckt, können Sie einfach „füllen“ das Array mit den Tagen zwischen An- und Abreise

{ 
    "id": "c223a991-b4e7-4333-ba45-a576010b568b", 
    "buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e", 
    "visitDateTimeUtc": ["2015-12-22T21:15:00Z", "2015-12-23T22:00:00Z", "2015-12-24T22:00:00Z", "2015-12-25T22:00:00Z" ] 
} 

auf diese Weise alle Daten des Intervalls berücksichtigt werden, indem Ihre date_histogram Aggregation.

1

Ich würde dieses Problem lösen, indem für VisitDays auf dem ES-Modell eine neue Array Eigenschaft, so dass, wenn jemand aus 01-Jan-2015 bis 05-Jan-2015 bleibt dann würde Ihr Modell so etwas wie diese:

{ 
    "id" : "c223a991-b4e7-4333-ba45-a576010b568b", 
    // other properties 
    "buildingId" : "48da1a81-fa73-4d4f-aa22-a5750162ed1e", 
    "arrivalDateTimeUtc" : "2015-01-01T21:15:00Z", 
    "departureDateTimeUtc" : "2015-01-05T22:00:00Z", // new property 
    "visitDays" : [ 
     "2015-01-01", 
     "2015-01-02", 
     "2015-01-03", 
     "2015-01-04", 
     "2015-01-05" 
    ] 
} 

Wenn Sie das getan haben, dann wäre Ihr Bucketing sehr einfach und sehr schnell. Ein Skriptfeld wäre nicht schnell. Und Sie sind zu 100% korrekt, dass der Versuch, dies in C# zu tun, nicht funktionieren würde, weil es viel zu langsam wäre.

Verwandte Themen