'Create term query on field contained in another field with elasticsearch-dsl-py

I am using elasticsearch-dsl-py and would like to filter on a term that is contained inside another one like this:

"slug": {
    "foo": "foo-slug",
    "bar": "bar-slug "
}

What I do is this :

search.query(‘filtered’, filter={"term": {"slug.foo": "foo-slug"}})

I would prefer something like

search.filter(term, slug.foo="foo-slug")

But I can’t as keyword can’t include dots.



Solution 1:[1]

If it helps anyone else, I had the same problem creating this kind of query against a child property not using nested objects. I found the solution was to use the query method instead of the filter method:

search.query('match', **{"slug.foo": "foo-slug"})

This worked for me in ElasticSearch 1.5.2.

Solution 2:[2]

edit... DON'T DO THIS: See aaronfay's answer for the correct approach.

This doesn't seem to be documented anywhere which is sad...

>>> search.filter('term', slug__foo='foo-slug').to_dict()
{'query': {'filtered': {'filter': {'term': {u'slug.foo': 'foo-slug'}}, 'query': {'match_all': {}}}}}

The double underscore will be converted into dot notation. No idea if this is stable.

Solution 3:[3]

So I am assuming that slug is a nested object in a larger document. In the current version (0.0.8) this can be achieved like so:

from elasticsearch_dsl import F

...

f = F('term', foo='foo-slug')
search = search.filter('nested', path='slug', filter=f)

Solution 4:[4]

It's a long time after the question had been asked, but just in case anyone comes across this post, Charles's answer is actually correct, (The method shouldn't break since it's actually mentioned in the packages docs now).

As the docs mention:

...,the Q shortcut (as well as the query, filter, and exclude methods on Search class) allows you to use __ (double underscore) in place of a dot in a keyword argument:

s = Search()
s = s.filter('term', category__keyword='Python')
s = s.query('match', address__city='prague')

It also mentions aaronfay's answer:

Alternatively you can always fall back to python’s kwarg unpacking if you prefer:

s = Search()
s = s.filter('term', **{'category.keyword': 'Python'})
s = s.query('match', **{'address.city': 'prague'})

Solution 5:[5]

This will do the trick for you:

args = {
    "slug.foo": "foo-slug"
}
search.filter(term, **args)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 aaronfay
Solution 2
Solution 3 aamiri
Solution 4 Bahman Rouhani
Solution 5 Adrian Gaudebert