Milan Stojanovic
Milan Stojanovic

Reputation: 307

Updating a property of an object in a list in ElasticSearch document?

I'm fairly new to ElasticSearch. I'm using it in a .NET project and I'm using NEST client. Right now I'm examining ways of handling document updates.

I have a document that looks like this:

public class Class1
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public List<Class2> PropList { get; set; }
}

and when I want to add something to the PropList, I'm doing it by script:

client.Update<Class1>(x => x
            .Id(1)
            .Index("index_name")
            .Script("ctx._source.propList += prop")
            .Params(p => p.Add("prop", newProp)));

That works perfectly right now. The problem is when I want to update a property of an object inside propList. The way I'm doing it right now is by retrieving the entire document, finding the object in the list, update the property and index the entire document again, which at some point can result in performance issues.

Is there a way of doing this more efficiently? Maybe using scripts or some other way?

Thanks.

Upvotes: 1

Views: 1917

Answers (1)

Sloan Ahrens
Sloan Ahrens

Reputation: 8718

I don't know how to set it up with nest, off-hand, but I would go with a parent/child relationship.

As a toy example, I set up an index with this mapping:

PUT /test_index
{
   "mappings": {
      "parent_type": {
         "properties": {
            "num_prop": {
               "type": "integer"
            },
            "str_prop": {
               "type": "string"
            }
         }
      },
      "child_type": {
         "_parent": {
            "type": "parent_type"
         },
         "properties": {
            "child_num": {
               "type": "integer"
            },
            "child_str": {
               "type": "string"
            }
         }
      }
   }
}

then added some data:

POST /test_index/_bulk
{"index":{"_type":"parent_type","_id":1}}
{"num_prop":1,"str_prop":"hello"}
{"index":{"_type":"child_type","_id":1,"_parent":1}}
{"child_num":11,"child_str":"foo"}
{"index":{"_type":"child_type","_id":2,"_parent":1}}
{"child_num":12,"child_str":"bar"}
{"index":{"_type":"parent_type","_id":2}}
{"num_prop":2,"str_prop":"goodbye"}
{"index":{"_type":"child_type","_id":3,"_parent":2}}
{"child_num":21,"child_str":"baz"}

Now if I want to update a child document I can just post a new version:

POST /test_index/child_type/2?parent=1
{
   "child_num": 13,
   "child_str": "bars"
}

(note that I have to provide the parent id so ES can route the request appropriately)

I can also do a partial, scripted update if I want to:

POST /test_index/child_type/3/_update?parent=2
{
   "script": "ctx._source.child_num+=1"
}

We can prove that this worked by searching the child types:

POST /test_index/child_type/_search
...
{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 3,
      "max_score": 1,
      "hits": [
         {
            "_index": "test_index",
            "_type": "child_type",
            "_id": "1",
            "_score": 1,
            "_source": {
               "child_num": 11,
               "child_str": "foo"
            }
         },
         {
            "_index": "test_index",
            "_type": "child_type",
            "_id": "2",
            "_score": 1,
            "_source": {
               "child_num": 13,
               "child_str": "bars"
            }
         },
         {
            "_index": "test_index",
            "_type": "child_type",
            "_id": "3",
            "_score": 1,
            "_source": {
               "child_num": 22,
               "child_str": "baz"
            }
         }
      ]
   }
}

Hope this helps. Here is the code I used, plus a few more examples:

http://sense.qbox.io/gist/73f6d2f347a08bfe0c254a977a4a05a68d2f3a8d

Upvotes: 1

Related Questions