2

I'm currently running into a problem, trying to build dynamic queries for Elasticsearch in Python. To make a query I use Q shortсut from elasticsearch_dsl. This is something I try to implement

...
s = Search(using=db, index="reestr")
condition = {"attr_1_":"value 1", "attr_2_":"value 2"} # try to build query from this
must = []
for key in condition:
    must.append(Q('match',key=condition[key]))

But that in fact results to this condition:

[Q('match',key="value 1"),Q('match',key="value 2")]

However, what I want is:

[Q('match',attr_1_="value 1"),Q('match',attr_2_="value 2")]

IMHO, the way this library does queries is not effective. I think this syntax:

Q("match","attrubute_name"="attribute_value")

is much more powerful and makes it possible to do a lot more things, than this one:

Q("match",attribute_name="attribute_value")

It seems, as if it is impossible to dynamically build attribute_names. Or it is, of course, possible that I do not know the right way to do it.

Jacobian
  • 10,122
  • 29
  • 128
  • 221
  • 1
    The only difference between `Q("match","attrubute_name"="attribute_value")` and `Q("match",attribute_name="attribute_value")` is the addition of quotes. How would adding quotes make it more powerful or possible to do more things? – neuronaut Jun 17 '15 at 19:15
  • It's not about quotes, it's about the way how the library interprets parameters. If we could build them dynamically (no problem in `MongoDb` for example), then it would be much more powerful tool. At this moment, I do not know the way how one builds dynamic queries for elastic. – Jacobian Jun 17 '15 at 19:21
  • 1
    Have you tried reading the [Elasticsearch documentation](https://www.elastic.co/guide/index.html)? Elasticsearch's RESTful API is very powerful (much more so than MongoDB) and can easily handle dynamically generated queries. I don't know what Python library you are using to interface with ES, but if it has limitations that won't let you do what you want you might consider using the RESTful API directly, or try another Python library. – neuronaut Jun 17 '15 at 19:37
  • Thanks, I will check it. As for library, I'm using elasticsearch_dsl. It greately simplifies the process of writing queries (in comparison to standard es.search etc.), but has its nuances, like the one that I address in my question. – Jacobian Jun 17 '15 at 19:44
  • Well, actually I found a solution =) The solution is to use `**` operator, like so: `Q('match',**{key:"value 2"})` where `key` can be a variable – Jacobian Jun 17 '15 at 20:03
  • @Jacobian Is that issue resolved – devanathan Oct 05 '16 at 09:55
  • Yeah) See the comment one line above – Jacobian Oct 06 '16 at 14:33
  • Might be helpful if you update your post or answer this question yourself and mark it accepted. This helped me tremendously. – Alec Gerona Feb 08 '18 at 06:56

1 Answers1

1

Suppose, filters = {'condition1':['value1'],'condition2':['value3','value4']}

Code:

    filters = data['filters_data'] 

    must_and = list() # The condition that has only one value
    should_or = list() # The condition that has more than 1 value

    for key in filters:
        if len(filters[key]) > 1:
            for item in filters[key]:
                should_or.append(Q("match", **{key:item})) 
        else:       
            must_and.append(Q("match", **{key:filters[key][0]})) 

    q1 = Bool(must=must_and)
    q2 = Bool(should=should_or)

    s = s.query(q1).query(q2) 
    result = s.execute()

One can also use terms, that can directly accept the list of values and no need of complicated for loops,

Code:

    for key in filters:
        must_and.append(Q("terms", **{key:filters[key]}))

    q1 = Bool(must=must_and)
Sachin
  • 103
  • 7