2017-03-15 2 views
0

Einfacher, meine Frage mit einem Usecase zu illustrieren, also lassen Sie uns die example aus dem elasticsearch guide.Filterung/Sortierung auf Unterschiede zwischen zwei Werten, die in verschachtelten Arrays enthalten sind (nur mit Skriptfilter und Doc-Werten)

Dies listet ein Produkt auf. Jedes Produkt hat eine verschachtelte Array Händler enthält, die Produkt sagte verkaufen:

{ 
     ... 

     "product" : { 
      "properties" : { 
       "resellers" : { 
        "type" : "nested", 
        "properties" : { 
         "name" : { "type" : "text" }, 
         "price" : { "type" : "double" } 
        } 
       } 
      } 
     } 
    } 

Wie würde ich das folgende, wenn überhaupt möglich machen?

  • Filtern Sie alle Produkte, bei denen storeA billiger ist als storeB. Z.B .: product.resellers[name=storeA].price < product.resellers[name=storeB].price
  • Bestellen Artikel von Differenz zwischen dem Preis von storeA und Speicher B

Dies muss wahrscheinlich ein Skript Filter und Ordnungsfilter jeweils, aber nicht sicher, wie ich über diese gehen würde. Darüber hinaus werden diese Arten von Abfragen häufig verwendet, so dass die Leistung wichtig ist. Daher muss ich wahrscheinlich bei DocValues ​​bleiben, anstatt auf _source zurückzugreifen. Ist das möglich? Ja

Antwort

1

, das ist auf jeden Fall möglich, und man kann es wie folgt tun:

{ 
    "sort": { 
    "_script": { 
     "type": "number", 
     "script": { 
     "inline": "def store1 = _source.resellers.find{it.name == store1}; def store2 = _source.resellers.find{it.name == store2}; (store1 != null && store2 != null) ? store1.price - store2.price : 0", 
     "lang": "groovy", 
     "params": { 
      "store1": "storeA", 
      "store2": "storeB" 
     } 
     }, 
     "order": "asc" 
    } 
    }, 
    "query": { 
    "bool": { 
     "filter": [ 
     { 
      "script": { 
      "script": { 
       "inline": "def store1 = _source.resellers.find{it.name == store1}; def store2 = _source.resellers.find{it.name == store2}; (store1 != null && store2 != null) ? store1.price < store2.price : false", 
       "lang": "groovy", 
       "params": { 
       "store1": "storeA", 
       "store2": "storeB" 
       } 
      } 
      } 
     } 
     ] 
    } 
    } 
} 

Die Art Skript sieht wie folgt aus:

def store1 = _source.resellers.find{it.name == store1}; 
def store2 = _source.resellers.find{it.name == store2}; 
(store1 != null && store2 != null) ? store1.price - store2.price : 0 

Das Filter Skript ein bisschen ähnlich ist und sieht wie folgt aus:

Beide Skripte nehmen zwei Parameter in der Eingabe, nämlich die Namen der Wiederverkäufer speichern Sie w Ameise zu vergleichen.

UPDATE

Irgendwie habe ich vergessen, zu erklären, warum es nicht möglich ist, es mit doc Werten zu tun. Dok-Werte sind effektiv die Umkehrung des invertierten Index, d. H. Zu jedem Dokument werden die Token abgebildet, die in diesem Dokument vorhanden sind. Dies in Verbindung mit der Tatsache, dass verschachtelte Dokumente als eigenständiges gespeichert sind (noch versteckt) Dokumente im Index, der doc-Wert für ein Dokument wie unten

{ 
    "id": 1, 
    "product": "Water", 
    "resellers": [ 
    { 
     "name": "storeA", 
     "price": 20 
    }, 
    { 
     "name": "storeB", 
     "price": 30 
    } 
    ] 
} 

würde wie folgt aussehen:

Document  | Values 
----------------+--------------------------- 
1 (top-level) | water 
1a (1st nested} | storea, 20 
1b (2nd nested} | storeb, 30 

Wenn man sich die obige Tabelle anschaut und Skripte im Zusammenhang mit jedem Dokument ausgeführt werden (ob auf oberster Ebene oder verschachtelt), wird offensichtlich, dass beim Zugriff auf doc-Werte innerhalb eines Skripts nur die Werte dieses Dokuments und damit auch die Werte ausgegeben werden Es ist nicht möglich, sie mit Werten aus einem anderen Dokument zu vergleichen.

Beim Zugriff auf die Quelle durchlaufen wir effektiv das Array resellers und es ist daher möglich, die Werte zwischen ihnen zu vergleichen und etwas zu liefern, das in Ihrem Kontext nützlich ist.

+0

Op hier erhöhen. Ich stimme zu, dass dies funktionieren würde, aber nach der ursprünglichen Frage suche ich nach einer Lösung, die doc-Werte enthält, anstatt '_source' zu ​​verwenden, da' _source' einen vollständigen Tabellen-Scan erfordert, der für meine Zwecke zu langsam wäre . Wenn das nicht möglich ist, würde ich einen gut erklärten Schnitt über das "Warum nicht" machen. Danke –

+1

Du hast Recht, irgendwie habe ich vergessen zu sagen, warum es nicht möglich ist, dies mit Doc-Werten zu tun. – Val

0

Das sieht wie ein Marktplatzproblem aus. So würde ich Produkte durch ihre Master-Produkt-IDs trennen - also Produkte können verschiedene Beschreibungen, Eigenschaften usw. haben - und fügen Sie ihnen Priorität zum Sortieren und Filtern.

{ 
     ... 

     "product" : { 
      "properties" : { 
       "masterProduct" : "int", 
       "priority" : "int", 
       "resellers" : { 

        "type" : "nested", 
        "properties" : { 
         "name" : { "type" : "text" }, 
         "price" : { "type" : "double" } 
        } 
       } 
      } 
     } 
    } 

Lassen Sie mich erklären, wie; Zuerst

product.resellers [name = storeA] .Preis < roduct.resellers [name = storeB] .Preis

Ich denke, das Problem wegen der von Ihnen aufgeworfenen wollen das billigste Produkt in die zeigen, Suchergebnis. Also ich denke, dass Sie alle Wiederverkäufer Preis haben sollten, während Produkte indexieren.

Und wenn Sie das billigste während Indexierung wissen, ist es Priorität eine positive Zahl wie 1. Und multiplizieren Sie andere Produkte mit -1, so dass Sie sie im Produkt Detail billig bis teuer sortieren können. Dies löst das zweite Problem (Bestellen Sie Produkte nach Differenz zwischen Preis von storeA und store B).

Immerhin haben Sie positive Prioritäten und negative Prioritäten in Ihrem Index. Und alles, was Sie einen Filter nach Priorität> 0 machen können, gibt Ihnen die billigsten Produkte zurück. Also nach Priorität, wenn irgendein Wiederverkäufer die Spitze vom Suchergebnis sein oder sich selbst fördern möchte, können Sie es tun, indem Sie priority

+0

Es ist kein "Marktplatz" -Problem. Ich muss beliebige Shops miteinander vergleichen, um ein Statistik-Dashboard zu erstellen. Wenn es aber wäre, wäre Ihre eine ziemlich elegante Lösung. –

Verwandte Themen