Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elasticsearch partial update with python

I have a elasticsearch document in the following format. I need to partial update the "x" field and add a python dict in it.

{
        "_index": "gdata34",
        "_type": "gdat",
        "_id": "328091-72341-118",
        "_version": 1,
        "_score": 1,
        "_source": {
            "d": {
                "Thursday": {
                    "s": ""
                },
                "Email": {
                    "s": ""
                },
               "Country": {
                    "s": "US"
                },

            },
            "x": {
                "Geo": {
                    "s": "45.335428,-118.057133",
                    "g": [
                        -118.057133
                        ,
                        45.335428
                    ]
                }
            },
          }
        }

I tried the following code to update:

from elasticsearch import Elasticsearch, exceptions
import pprint


elasticsearch = Elasticsearch()
doc = elasticsearch.get(index='gdata34', doc_type='gdat', id='328091-72341-7')

elasticsearch.update(index='gdata34', doc_type='gdat', id='328091-72341-7',
                     body={"script":"ctx._source.x += y",
                           "params":{"y":"z"}
                     }
                     )
elasticsearch.indices.refresh(index='gdata34')
new_doc = elasticsearch.get(index='gdata34', doc_type='gdat', id='328091-72341-7')

I am getting this error:

elasticsearch.exceptions.RequestError: TransportError(400, u'ElasticsearchIllegalArgumentException[failed to execute script]; nested: ScriptException[dynamic scripting for [groovy] disabled]; ')

What is the right way to do partial update in elasticsearch using python?

like image 928
Anish Avatar asked Apr 06 '15 10:04

Anish


Video Answer


2 Answers

For future reference, the following method of partial update worked.

elasticsearch.update(index='gdata34', doc_type='gdat', id='328091-72341-7',
                     body={
                         'doc': {'x': {'y':'z'}}
                     }
                     )
like image 50
Anish Avatar answered Oct 15 '22 20:10

Anish


From the ElasticSearch docs on scripting:

We recommend running Elasticsearch behind an application or proxy, which protects Elasticsearch from the outside world. If users are allowed to run dynamic scripts (even in a search request), then they have the same access to your box as the user that Elasticsearch is running as. For this reason dynamic scripting is allowed only for sandboxed languages by default.

Now, in recent ES version there has been a bug in the vulnerability in the Groovy scripting engine that allows scripts to escape the sandbox and execute shell commands as the user running the Elasticsearch Java VM - that's why the Groovy sandbox is disabled by default in recent versions, and therefore the execution of Groovy scripts passed in the request body or from the .scripts index. The only way to execute Groovy scripts with this default configuration is to place them in the config/scripts/ directory on the node.

So you have two options:

  • If your ES instance is not directly accessible and is secured behind a proxy, you can turn on Groovy sandboxing again by setting script.groovy.sandbox.enabled: true in config/elasticsearch.yml on your node(s). If your ES instance is accessible by your
  • You can prepare your script and place it on the filesystem in the config/scripts directory of your node(s), and call it by name. See Running Groovy Scripts without Dynamic Scripting for details.
like image 41
Lukas Graf Avatar answered Oct 15 '22 20:10

Lukas Graf