Как точно представить этот запрос ElasticSearch с помощью NEST?

Предыстория/Цель

У меня есть запрос в ElasticSearch, где я использую фильтры для нескольких полей (относительно небольшой набор данных, и мы точно знаем, какие значения должны быть в этих полях во время запроса). Идея состоит в том, что мы выполним полнотекстовый запрос, но только после того, как отфильтруем некоторые выборки, сделанные пользователем.

Я разместил ElasticSearch за контроллером WebAPI и решил, что для выполнения запроса имеет смысл использовать NEST.

Запрос на простом английском

У нас есть фильтры для нескольких полей. Каждый внутренний фильтр является фильтром или, но вместе они представляют собой И.

В SQL эквивалентом псевдокода будет select * from table where foo in (1,2,3) AND bar in (4,5,6).

Вопросы

  • Могу ли я упростить то, как я думаю об этом запросе, основываясь на том, что вы видите ниже? Я упускаю из виду какой-то базовый подход? Это кажется тяжелым, но я новичок в ES.
  • Как правильно представить приведенный ниже запрос в синтаксисе NEST?
  • Является ли NEST лучшим выбором для этого? Должен ли я вместо этого использовать библиотеку ElasticSearch и переходить на более низкий уровень?

Текст запроса

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "must": [
            {
              "or": [
                { "term": { "foo": "something" } },
                { "term": { "foo": "somethingElse" } }
              ]
            },
            {
              "or": [
                { "term": { "bar": "something" } },
                { "term": { "bar": "somethingElse" } }
              ]
            }
          ]
        }
      }
    }
  },

  "size": 100
}

person SeanKilleen    schedule 31.08.2015    source источник


Ответы (1)


Такого рода задачи достаточно просты и популярны в ES. Вы можете представить это в NEST следующим образом:

var rs = es.Search<dynamic>(s => s
            .Index("your_index").Type("your_type")
            .From(0).Size(100)
            .Query(q => q
                .Filtered(fq => fq
                    .Filter(ff => ff
                        .Bool(b => b
                            .Must(
                                m1 => m1.Terms("foo", new string[] { "something", "somethingElse" }),
                                m2 => m2.Terms("bar", new string[] { "something", "somethingElse" })
                            )
                        )
                    )
                    .Query(qq => qq
                        .MatchAll()
                    )
                )
            )
        );

Некоторые примечания:

  • Я использую отфильтрованный запрос, чтобы сначала отфильтровать то, что мне нужно, а затем искать вещи. В этом случае он будет фильтровать foo in ("something", "somethingElse") AND bar in ("something", "somethingElse"), а затем запрашивать все отфильтрованные результаты (match_all). Вы можете изменить match_all на то, что вам нужно. filtered query это для лучшей производительности, так как ES нужно будет оценивать только несколько документов в query части (после фильтрации), а не все документы.
  • Я использую фильтр terms, более простой и производительный, чем or. Режим по умолчанию для terms — ИЛИ для всех входных терминов, вы можете узнать больше о доступных режимах в документе (И, ИЛИ, ОБЫЧНЫЙ, ...).

На мой взгляд, Nest — лучший выбор для .NET, поскольку он разработан для простых и удобных целей. Я использовал более низкий API только в том случае, если хочу использовать новые функции, которые Nest не поддерживает в то время, или если у Nest есть ошибки в функциях, которые я использую. Краткое руководство по NEST можно найти здесь: http://nest.azurewebsites.net/nest/writing-queries.html

Обновлено: создание динамических фильтров bool:

var filters = new List<Nest.FilterContainer>();
filters.Add(Nest.Filter<dynamic>.Terms("foo", new string[] { "something", "somethingElse" }));
// ... more filter

затем замените .Bool(b => b.Must(...)) на .Bool(b => b.Must(filters.ToArray()))

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

person Duc.Duong    schedule 31.08.2015
comment
Это очень полезная отправная точка - спасибо! что, если бы мне нужно было вычислить обязательные требования (ваши m1 и m2 выше) на лету? Например, их может быть 3 или 1, и я должен составлять их отдельно в зависимости от того, какие фильтры передаются? Будет ли пустой массив в определении Must соответствовать всем документам или только документам, в которых эти поля пусты? Еще раз спасибо за ваш отличный ответ. - person SeanKilleen; 31.08.2015
comment
Вы можете сначала определить список фильтров, а затем передать его Bool, я обновил ответ. В случае пустого массива он будет подавлен NEST и равен всем. - person Duc.Duong; 31.08.2015
comment
К вашему сведению. Если вы хотите запросить поля с пустыми значениями, вы можете попробовать фильтр missing (elastic.co/guide/en/elasticsearch/reference/current/) - person Duc.Duong; 31.08.2015
comment
Обновление было именно тем, что мне нужно было увидеть. Большое спасибо, что нашли время, чтобы уточнить. - person SeanKilleen; 31.08.2015