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. Условие 1: Книги, которые имеют автора "X" и isbn "1"
  2. Условие 2: Книги, которые имеют автора "X" и isbn "2"
  3. Условие 3: Книги, которые имеют автора "Z" и isbn "3"
  4. Другие условия: .....

Теперь фильтр во вложенном Query должен получать книги, если:
Условие 1 И Условие 2 Или Условие 3

Предположим, что у меня есть имя класса FilterOptions, которое содержит следующие атрибуты:

  1. FieldName
  2. Значение
  3. Оператор (который объединит следующий фильтр)

Я собираюсь зациклить данный массив 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

Надеюсь это поможет.

Другие вопросы по тегам