Nest Elastic - Построение динамического вложенного запроса
Я должен запросить вложенный объект, используя Nest, однако запрос построен динамически. Ниже приведен код, демонстрирующий использование запроса к вложенным "книгам" статическим способом.
QueryContainer qry;
qry = new QueryStringQuery()
{
DefaultField = "name",
DefaultOperator = Operator.And,
Query = "salman"
};
QueryContainer qry1 = null;
qry1 = new RangeQuery() // used to search for range ( from , to)
{
Field = "modified",
GreaterThanOrEqualTo = Convert.ToDateTime("21/12/2015").ToString("dd/MM/yyyy"),
};
QueryContainer all = qry && qry1;
var results = elastic.Search<Document>(s => s
.Query(q => q
.Bool(qb => qb
.Must(all)))
.Filter(f =>
f.Nested(n => n
.Path("books")
.Filter(f3 => f3.And(
f1 => f1.Term("book.isbn", "122"),
f2 => f2.Term("book.author", "X"))
)
)
)
);
Проблема в том, что мне нужно объединить несколько запросов (используя операторы И, ИЛИ) для "книг" в динамическом режиме. Например, получите книги, которые удовлетворяют следующим условиям:
- Условие 1: Книги, которые имеют автора "X" и isbn "1"
- Условие 2: Книги, которые имеют автора "X" и isbn "2"
- Условие 3: Книги, которые имеют автора "Z" и isbn "3"
- Другие условия: .....
Теперь фильтр во вложенном Query должен получать книги, если:
Условие 1 И Условие 2 Или Условие 3
Предположим, что у меня есть имя класса FilterOptions, которое содержит следующие атрибуты:
- FieldName
- Значение
- Оператор (который объединит следующий фильтр)
Я собираюсь зациклить данный массив FilterOptions, чтобы построить запрос.
Вопрос:
Что я должен использовать для создания вложенного запроса? Это FilterDesciptor и как их объединить добавить вложенный запрос в метод поиска?
Пожалуйста, порекомендуйте какую-нибудь ценную ссылку или пример?
2 ответа
Я согласен с paweloque, кажется, что ваши первые два условия противоречивы и не сработают, если вы соберете их вместе. Игнорируя это, вот мое решение. Я реализовал это таким образом, чтобы учесть более трех конкретных условий, которые у вас есть. Я тоже чувствую, что это будет соответствовать лучше в bool
заявление.
QueryContainer andQuery = null;
QueryContainer orQuery = null;
foreach(var authorFilter in FilterOptions.Where(f=>f.Operator==Operator.And))
{
andQuery &= new TermQuery
{
Field = authorFilter.FieldName,
Value = authorFilter.Value
};
}
foreach(var authorFilter in FilterOptions.Where(f=>f.Operator==Operator.Or))
{
orQuery |= new TermQuery
{
Field = authorFilter.FieldName,
Value = authorFilter.Value
};
}
После этого в .Nested
позвони я бы поставил
.Path("books")
.Query(q=>q
.Bool(bq=>bq
.Must(m=>m.MatchAll() && andQuery)
.Should(orQuery)
))
В конкретном случае Condition 1
а также Condition 2
вы, вероятно, не получите никаких результатов, потому что это исключительные условия. Но теперь я предполагаю, что вы хотите получить результаты, соответствующие любому из этих условий. Вы выбрали вложенный, который определенно является подходящим способом. С помощью вложенного типа вы можете комбинировать параметры для одной книги.
Объединение вложенных запросов
Для вашего случая использования я бы использовал bool
тип запроса с must
или же should
статьи. Запрос, чтобы получить книги для любого Condition 1
или же Condition 2
было бы:
POST /books/_search
{
"query": {
"bool": {
"should": [
{
"nested": {
"path": "books",
"query": {
"bool": {
"must": [
{
"match": {
"books.isbn": "2"
}
},
{
"match": {
"books.author": "X"
}
}
]
}
}
}
},
{
"nested": {
"path": "books",
"query": {
"bool": {
"must": [
{
"match": {
"books.isbn": "1"
}
},
{
"match": {
"books.author": "X"
}
}
]
}
}
}
}
]
}
}
}
Можете ли вы объяснить, почему ваши книги вложены? Не вкладывая их в верхнюю структуру, а непосредственно индексируя как объект верхнего уровня в индексе / типе, вы можете упростить свои запросы.
Не-Исследуемый
Есть еще одно предостережение, о котором вы должны напомнить: если вы хотите иметь точное совпадение с автором и ISBN, вы должны убедиться, что поля ISBN и author установлены в not_analyzed
, В противном случае они будут проанализированы и разбиты на части, и ваш матч не будет работать очень хорошо.
Например, если у вас есть номер ISBN с черточками, он будет разбит на части:
978-3-16-148410-0
будет проиндексирован как:
978
3
16
148410
0
И поиск с точно таким же номером ISBN даст вам все книги, у которых есть один из вспомогательных номеров в их номере ISBN. Если вы хотите предотвратить это, используйте not_analyzed
index-type и Multi-поля:
"isbn": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
}
Затем для решения not_analyzed
Поле isbn, которое вы должны назвать:
books.isbn.raw
Надеюсь это поможет.