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.

8
  • 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? Commented Jun 17, 2015 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. Commented Jun 17, 2015 at 19:21
  • 1
    Have you tried reading the Elasticsearch documentation? 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. Commented Jun 17, 2015 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. Commented Jun 17, 2015 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 Commented Jun 17, 2015 at 20:03

1 Answer 1

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)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.