Динамический эластичный поисковый запрос в С# NEST

Недавно начал работать над NEST API для эластичного поиска, застрял на следующем запросе, data.e будет динамически заполняться с использованием ввода от клиента в HttpGet, например: пользователь отправляет eventA, eventB, eventC, тогда мы добавим в часть должен :

GET events/_search
{
  "_source": false, 
  "query": {
    "bool": {
      "must": [
        {"range": {
          "timestamp": {
            "gte": 1604684158527,
            "lte": 1604684958731
            }
        }},
        {"nested": {
          "path": "data",
          "query": {
            "bool": {
              "should": [
                {"match": {
                   "data.e": "eventA"
                }},
                {"match": {
                  "data.e": "eventB"
                }},
                {"match": {
                   "data.e": "eventC"
                }},
              ]
            }
            },
          "inner_hits": {} 
        }}
      ]
    }
  }
}

Вот что я придумал до сих пор:

var graphDataSearch = _esClient.Search<Events>(s => s
                .Source(src => src
                    .Includes(i => i
                        .Field("timestamp")
                        )
                 )
                .Query(q => q
                    .Bool(b => b
                        .Must(m => m
                                .Range(r => r
                                    .Field("timestamp")
                                    .GreaterThanOrEquals(startTime)
                                    .LessThanOrEquals(stopTime)
                                    ),
                                m => m
                                .Nested(n => n
                                    .Path("data")
                                    .Query(q => q
                                        .Bool(bo => bo
                                            .Should(
                                            // what to add here?
                                    )
                                    )
                                )
                        )
                    )
                ));

Может кто-нибудь помочь, как динамически построить часть should на основе того, что отправляет пользователь?

Спасибо.


person Ghanendra    schedule 18.11.2020    source источник


Ответы (1)


Вы можете заменить вложенный запрос в приведенном выше фрагменте, как показано ниже.

// You may modify the parameters of this method as per your needs to reflect user input
// Field can be hardcoded as shown here or can be fetched from Event type as below
// m.Field(f => f.Data.e)

public static QueryContainer Blah(params string[] param)
{
    return new QueryContainerDescriptor<Events>().Bool(
        b => b.Should(
            s => s.Match(m => m.Field("field1").Query(param[0])),
            s => s.Match(m => m.Field("field2").Query(param[1])),
            s => s.Match(m => m.Field("field3").Query(param[2]))));
}

По сути, здесь мы возвращаем объект QueryContainer, который будет передан во вложенный запрос.

.Query(q => Blah(<your parameters>))

То же самое можно сделать, добавив этот встроенный метод без отдельного метода. Вы можете выбрать, какой маршрут вы предпочитаете. Однако, в целом, наличие собственного метода повышает читабельность и сохраняет чистоту.

Подробнее об использовании Match можно прочитать здесь.

Редактировать:

Поскольку вы хотите динамически добавлять туда запросы на совпадение, ниже описан способ, которым вы можете это сделать.

private static QueryContainer[] InnerBlah(string field, string[] param)
{
    QueryContainer orQuery = null;
    List<QueryContainer> queryContainerList = new List<QueryContainer>();
    foreach (var item in param)
    {
        orQuery = new MatchQuery() {Field = field, Query = item};
        queryContainerList.Add(orQuery);
    }
    return queryContainerList.ToArray();
}

Теперь вызовите этот метод изнутри вышеуказанного метода, как показано ниже.

public static QueryContainer Blah(params string[] param)
{
    return new QueryContainerDescriptor<Events>().Bool(
        b => b.Should(
            InnerBlah("field", param)));
}
person Sai Gummaluri    schedule 19.11.2020
comment
Часть внутри должна () должна быть создана динамически, пользователь может отправить 4 события или 5 событий, поэтому мы также должны сопоставить их, опубликованное вами решение жестко запрограммировано только для 3 типов параметров, которые я показал в качестве примера. - person Ghanendra; 19.11.2020
comment
Вы можете перебрать отправленные элементы и сгенерировать внутренний запрос соответствия внутри should. Отредактирует ответ, чтобы указать, как это сделать. - person Sai Gummaluri; 19.11.2020
comment
@Ghanendra — добавлена ​​логика динамической генерации для запросов с несколькими совпадениями. - person Sai Gummaluri; 19.11.2020
comment
Спасибо за помощь! Мне пришлось немного изменить ваш код на следующий private QueryContainer[] InnerBlah(string field, List<string> param) { QueryContainer orQuery = null; List<QueryContainer> lq = new List<QueryContainer>(); foreach (string item in param) { orQuery = new MatchQuery() { Field = field, Query = item }; lq.Add(orQuery); } return lq.ToArray(); } , в противном случае он создавал несколько элементов should[bool( в запросе json - person Ghanendra; 20.11.2020
comment
Пожалуйста, обновите свой ответ, и я отмечу его как принятый. - person Ghanendra; 20.11.2020
comment
@ Ганендра - Ах! Правда что. Я исправил ответ, чтобы отразить изменение. Ваше здоровье! - person Sai Gummaluri; 21.11.2020