2014-10-08 17 views
9

Tôi đã được yêu cầu để loại bỏ đối tượng từ mảng thỏa mãn điều kiện, tôi có thể cập nhật các đối tượng của mảng trên cơ sở điều kiện, đó là như sau:loại bỏ các đối tượng từ mảng tìm kiếm đàn hồi

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"} 
} 

này đang làm việc

cho remove tôi đang làm điều này

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" } 
} 

nhưng điều này không làm việc và đưa ra lỗi này,

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

tôi có thể loại bỏ toàn bộ mảng hoặc toàn bộ lĩnh vực sử dụng

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

Tôi cũng có thể loại bỏ đối tượng từ mảng bằng cách xác định tất cả các phím của một đối tượng sử dụng

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

nút của tôi phiên bản tìm kiếm đàn hồi của mô-đun là 2.4.2 máy chủ tìm kiếm đàn hồi là 1.3.2

Trả lời

14

Bạn nhận được điều đó vì bạn đang cố sửa đổi danh sách trong khi lặp qua nó, có nghĩa là bạn muốn thay đổi danh sách đối tượng và đồng thời liệt kê các đối tượng đó.

Bạn thay vì cần phải làm điều này:

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"} 
} 

Nếu bạn có nhiều hơn một mục phù hợp với tiêu chuẩn, sử dụng một danh sách thay vì:

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

Cảm ơn Andrei Stefan, Đây là làm việc, nếu danh sách chứa chỉ có một đối tượng của tweet_id = 123 , nhưng điều này không làm việc, nếu tôi muốn loại bỏ nhiều đối tượng có cùng tweet_id = 123, những gì tôi đã yêu cầu để làm cho điều đó ??? –

+1

Vâng, thật dễ dàng. Xem phản hồi được cập nhật của tôi. –

+0

Ngoài ra, tôi sẽ đánh giá cao nếu bạn có thể upvote câu trả lời. –

7

Đối với những người cần làm việc này trong elasticsearch 2.0 trở lên, nilforeach không được công nhận bởi groovy.

Vì vậy, đây là phiên bản cập nhật, bao gồm tùy chọn thay thế một mục có cùng id của một đối tượng mới.

và cũng đi qua nó là upsert sẽ đảm bảo mục được thêm ngay cả khi tài liệu không tồn tại được nêu

{ 
    "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

bạn tiết kiệm cho tôi lớn thời gian bro ... Bạn chỉ là tuyệt vời ... –

+1

Bạn cũng có thể thêm vào trong ngôn ngữ rãnh để loại bỏ nhiều hơn một giá trị dưới dạng danh sách thay vì xóa một lần? –

Các vấn đề liên quan