Фильтрация по нескольким полям в Elasticsearch ObjectField()
У меня возникают проблемы с определением синтаксиса фильтрации для ObjectFields() в django-elasticsearch-dsl. В частности, когда я пытаюсь фильтровать по нескольким подполям одного и того же ObjectField(), я получаю неправильные результаты.
Например, рассмотрим следующий документ
class ItemDocument(Document):
product = fields.ObjectField(properties={
'id': fields.IntegerField(),
'name': fields.TextField(),
'description': fields.TextField()
})
details = fields.ObjectField(properties={
'category_id': fields.IntegerField(),
'id': fields.IntegerField(),
'value': fields.FloatField()
})
description = fields.TextField()
Я хочу найти элемент с детальным объектом, который имеет category_id == 3
и value < 1.5
, поэтому я создал следующий запрос
x = ItemDocument.search().filter(Q("match",details__category_id=3) & Q("range",details__value={'lt':1.5})).execute()
К сожалению, это возвращает все элементы, которые имеют объект детализации с category_id==3
и отдельный объект детализации с value < 1.5
, например,
{
"product": ...
"details": [
{
"category_id": 3,
"id": 7,
"value": 20.0
},
{
"category_id": 4,
"id": 7,
"value": 1.0
},
...
]
}
вместо желаемого результата всех элементов, которые имеют объект детализации с category_id==3
и value < 1.5
, например,
{
"product": ...
"details": [
{
"category_id": 3,
"id": 7,
"value": 1.0
},
...
]
}
Как правильно оформить этот запрос с помощью django-elasticsearch-dsl?
Вы можете использовать вложенный запрос в Elasticsearch для фильтрации по нескольким подполям одного и того же поля ObjectField. Вот пример того, как это можно сделать в django-elasticsearch-dsl:
x = ItemDocument.search().query(
"nested",
path="details",
query=Q("match", details__category_id=3) & Q("range", details__value={'lt':1.5})
).execute()
Вложенный запрос позволяет фильтровать по нескольким подполям объекта details и возвращать только документы, в которых есть объект detail с category_id==3 и значением < 1.5.
Вы также можете использовать опцию inner_hits с вложенным запросом, чтобы получить подробную информацию о совпадающих детальных объектах:
x = ItemDocument.search().query(
"nested",
path="details",
query=Q("match", details__category_id=3) & Q("range", details__value={'lt':1.5}),
inner_hits={}
).execute()
Это добавит вложенное поле к каждому результату поиска, которое содержит сведения о совпадающих объектах деталей. Вы можете получить доступ к этому полю в своем коде следующим образом:
results = x.to_dict()
for result in results['hits']['hits']:
nested_results = result['inner_hits']['details']['hits']['hits']
# do something with nested_results