2

I'm trying to build dynamically a query for ElasticSearch, here is my code:

import json

query_string = "person human"

query = {}

query['query'] = {}
query['query']['bool']  = {}
query['query']['bool']['must']  = {}

must_string = []
term_string = {}
term_string['term'] = {}
term_string['term']["labels.Name"] = ""

for term in query_string.split():
    term_string['term']["labels.Name"] = term
    must_string.append(term_string)

query['query']['bool']['must'] = must_string

print(json.dumps(query))

I was expecting an output like this:

{"query": {"bool": {"must": [{"term": {"labels.Name": "person"}}, {"term": {"labels.Name": "human"}}]}}}

but instead i'm getting this :

{"query": {"bool": {"must": [{"term": {"labels.Name": "human"}}, {"term": {"labels.Name": "human"}}]}}}

Note the duplicated value in labels.Name.

There is a problem when I'm appending in the list and that's overwriting the previous value.

martineau
  • 119,623
  • 25
  • 170
  • 301
user1297406
  • 1,241
  • 1
  • 18
  • 36

3 Answers3

2

The problem is not the list but the dictionnary : you update the value of

term_string['term']["labels.Name"]

at each iteration of your for loop. You could replace

term_string['term']["labels.Name"] = term

by something like:

term_string = {'term':{'labels.name':term}}
1

You are appending the same dictionary to your list each time. The reference is to one dictionary only. You can reference a new dictionary by constructing a new dictionary each time:

for term in query_string.split(): 
    term_string = {}
    term_string['term'] = {}
    term_string['term']["labels.Name"] = ""
    term_string['term']["labels.Name"] = term
    must_string.append(term_string)

For construction of a nested dictionary, I recommend you utilize collections.defaultdict: see defaultdict of defaultdict, nested.

jpp
  • 159,742
  • 34
  • 281
  • 339
0

Python dictionaries are passed by reference. Which means that when you append to must_string you are really appending a reference to the term_string dictionary, so that when you modify the term_string dictionary in the following loop it changes the underlying dictionary and not just the last version.

To get do what you want, you'll need to make a new dictionary for every loop to append, or you could do a deepcopy() (from the copy library) of your dictionary before you append it.

MisterSheep
  • 67
  • 1
  • 5