2014-10-08 5 views
9

I erforderlich sind Gegenstand von Array zu entfernen, die die Bedingung erfüllt, ich bin in der Lage, das Objekt von Array auf der Grundlage der Bedingung zu aktualisieren, die wie folgt lautet:Objekte aus Array Elasticsearch entfernen

PUT twitter/twit/1 
{"list": 
    [ 
     { 
      "tweet_id": "1", 
      "a": "b" 
     }, 
     { 
      "tweet_id": "123", 
      "a": "f" 
     } 
    ] 
} 

POST /twitter/twit/1/_update 
{"script":"foreach (item :ctx._source.list) { 
       if item['tweet_id'] == tweet_id) { 
         item['new_field'] = 'ghi'; 
       } 
      }", 
"params": {tweet_id": 123"} 
} 

dieses arbeitet ich dieses

POST /twitter/twit/1/_update 
{ "script": "foreach (item : ctx._source.list) { 
        if item['tweet_id'] == tweet_id) { 
          ctx._source.list.remove(item); 
        } 
      }", 
    "params": { tweet_id": "123" } 
} 

für entfernen tue, aber das funktioniert nicht, und diesen Fehler geben,

ElasticsearchIllegalArgumentException[failed to execute script]; nested: ConcurrentModificationException; Error: ElasticsearchIllegalArgumentException[failed to execute script]; nested: ConcurrentModificationException

Ich bin in der Lage ganze Reihe oder ganze Feld zu entfernen, mit

"script": "ctx._source.remove('list')" 

Ich bin auch durch die Angabe alle Schlüssel eines Objekts mit

"script":"ctx._source.list.remove(tag)", 
    "params" : { 
     "tag" : {"tweet_id": "123","a": "f"} 

mein Knotenobjekt aus dem Array entfernen können Modul elastische Suche Version ist 2.4.2 elastische Suche Server ist 1.3.2

Antwort

14

Sie bekommen das, weil Sie versuchen, eine Liste zu ändern, während es durchlaufen, was Sie wollen Ändern Sie eine Objektliste und listen Sie gleichzeitig diese Objekte auf.

Sie stattdessen brauchen, dies zu tun:

POST /twitter/twit/1/_update 
{ 
    "script": "item_to_remove = nil; foreach (item : ctx._source.list) { if (item['tweet_id'] == tweet_id) { item_to_remove=item; } } if (item_to_remove != nil) ctx._source.list.remove(item_to_remove);", 
    "params": {"tweet_id": "123"} 
} 

Wenn Sie mehr als ein Element, das den Kriterien entspricht, wird eine Liste verwenden statt:

POST /twitter/twit/1/_update 
{ 
    "script": "items_to_remove = []; foreach (item : ctx._source.list) { if (item['tweet_id'] == tweet_id) { items_to_remove.add(item); } } foreach (item : items_to_remove) {ctx._source.list.remove(item);}", 
    "params": {"tweet_id": "123"} 
} 
+1

Dank Andrei Stefan existiert, das funktioniert, wenn die Liste nur ein Objekt von tweet_id = 123 enthält , aber das funktioniert nicht, wenn ich mehrere Objekte entfernen möchte, die die selbe tweet_id = 123 haben, was habe ich dafür zu tun ??? –

+1

Nun, das ist einfach. Sehen Sie meine aktualisierte Antwort. –

+0

Außerdem würde ich mich freuen, wenn Sie die Antwort verbessern könnten. –

7

Für Menschen, die diese Arbeit in Elasticsearch brauchen 2.0 und höher, die nil und foreach werden nicht von groovy erkannt.

Also hier ist eine aktualisierte Version, einschließlich einer Option, ein Element durch die gleiche ID durch ein neues Objekt zu ersetzen.

und auch die upsert machen vorbei sicherzustellen, das Element hinzugefügt wird, selbst wenn das Dokument noch nicht

{ 
    "script": "item_to_remove = null; ctx._source.delivery.each { elem -> if (elem.id == item_to_add.id) { item_to_remove=elem; } }; if (item_to_remove != null) ctx._source.delivery.remove(item_to_remove); if (item_to_add.size() > 1) ctx._source.delivery += item_to_add;", 
    "params": {"item_to_add": {"id": "5", "title": "New item"}}, 
    "upsert": [{"id": "5", "title": "New item"}] 
} 
+0

Sie gespeichert mir große Zeit bro ... Sie sind einfach genial ... –

+1

Können Sie bitte auch in Groove-Sprache, um mehr als eine zu entfernen Werte als Liste statt einzeln entfernen? –