NEST - MultiMatch ищет все документы, когда термин пуст - Elasticsearch 6.4 - PullRequest
0 голосов
/ 09 ноября 2018

Я пытаюсь выполнить запрос, используя NEST и параметр multimatch, но результаты не соответствуют ожидаемым.

Я отправляю термин, который нужно сравнить с несколькими полями. Однако, если вы не зададите условие поиска, все документы должны быть возвращены.

Я видел, что можно использовать ключевое слово типа "*. *", Но оно не сработало. Любое предложение?

var searchResponse = client.Search<DocumentElasticModel>(s => s
              .Size(pageSize)
              .Skip(currentPageIndex * pageSize)
              .Sort(ss => ss
                .Descending(SortSpecialField.Score)
              )
              .Source(sf => sf
                .Includes(i => i
                    .Fields(
                        returnedFields
                    )
                )
              )
              .Query(q => q
                .Nested(c => c
                    .Name("named_query")
                    .Boost(1.1)
                    .InnerHits(i => i.Explain())
                    .Path(p => p.PerguntasRespostas)
                    .Query(nq => nq
                        .MultiMatch(m => m
                            .Fields(f => filterFields) 
-----------------------WHEN THE 'SEARCH' IS EMPTY, SHOULD FIND ALL -----------------
                            .Query(string.IsNullOrEmpty(search) ? string.Empty : search)
                        )
                    )
                    .IgnoreUnmapped()
                )
              )

1 Ответ

0 голосов
/ 10 ноября 2018

NEST поддерживает это по умолчанию с концепцией, именуемой Безусловные запросы . Вы можете

private static void Main()
{
    var defaultIndex = "documents";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    var settings = new ConnectionSettings(pool, new InMemoryConnection())
        .DefaultIndex(defaultIndex)
        .DisableDirectStreaming()
        .PrettyJson()
        .OnRequestCompleted(callDetails =>
        {
            if (callDetails.RequestBodyInBytes != null)
            {
                Console.WriteLine(
                    $"{callDetails.HttpMethod} {callDetails.Uri} \n" +
                    $"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
            }
            else
            {
                Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
            }

            Console.WriteLine();

            if (callDetails.ResponseBodyInBytes != null)
            {
                Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                         $"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
                         $"{new string('-', 30)}\n");
            }
            else
            {
                Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                         $"{new string('-', 30)}\n");
            }
        });

    var client = new ElasticClient(settings);

    var pageSize = 20;
    var currentPageIndex = 0;  
    string search = "foo";


    var searchResponse = client.Search<DocumentElasticModel>(s => s
        .Size(pageSize)
        .Skip(currentPageIndex * pageSize)
        .Sort(ss => ss
            .Descending(SortSpecialField.Score)
        )
        .Source(sf => sf
            .Includes(i => i
                .Fields(f => f.TopLevelMessage)
            )
        )
        .Query(q => q
            .Nested(c => c
                .Name("named_query")
                .Boost(1.1)
                .InnerHits(i => i.Explain())
                .Path(p => p.PerguntasRespostas)
                .Query(nq => nq
                    .MultiMatch(m => m
                        .Fields(f => f
                            .Field(ff => ff.PerguntasRespostas.First().Message)
                        ) 
                        .Query(search)
                    )
                )
                .IgnoreUnmapped()
            )
        )
    );
}


public class DocumentElasticModel 
{
    public string TopLevelMessage { get; set; }

    public IEnumerable<PerguntasRespostas> PerguntasRespostas {get;set;}
}

public class PerguntasRespostas
{
    public string Message { get; set; }  
}

Это отправит следующий запрос

POST http://localhost:9200/documents/documentelasticmodel/_search
{
  "from": 0,
  "size": 20,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "_source": {
    "includes": [
      "topLevelMessage"
    ]
  },
  "query": {
    "nested": {
      "_name": "named_query",
      "boost": 1.1,
      "query": {
        "multi_match": {
          "query": "foo",
          "fields": [
            "perguntasRespostas.message"
          ]
        }
      },
      "path": "perguntasRespostas",
      "inner_hits": {
        "explain": true
      },
      "ignore_unmapped": true
    }
  }
}

Теперь, если вы измените search на string.Empty или null, вы получите

POST http://localhost:9200/documents/documentelasticmodel/_search
{
  "from": 0,
  "size": 20,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "_source": {
    "includes": [
      "topLevelMessage"
    ]
  }
}

Без явного "query" в запросе, это то же самое, что и запрос match_all.

Если вы хотите переопределить функцию безусловного запроса в NEST, вы можете пометить запрос как .Verbatim(), и NEST отправит точно так же, как

var searchResponse = client.Search<DocumentElasticModel>(s => s
    .Size(pageSize)
    .Skip(currentPageIndex * pageSize)
    .Sort(ss => ss
        .Descending(SortSpecialField.Score)
    )
    .Source(sf => sf
        .Includes(i => i
            .Fields(f => f.TopLevelMessage)
        )
    )
    .Query(q => q
        .Nested(c => c
            .Verbatim() // <-- mark the nested query
            .Name("named_query")          
            .Boost(1.1)
            .InnerHits(i => i.Explain())
            .Path(p => p.PerguntasRespostas)
            .Query(nq => nq
                .MultiMatch(m => m
                    .Verbatim() // <-- mark the inner query
                    .Fields(f => f
                        .Field(ff => ff.PerguntasRespostas.First().Message)
                    ) 
                    .Query(search)
                )
            )
            .IgnoreUnmapped()
        )
    )
);

который отправляет

POST http://localhost:9200/documents/documentelasticmodel/_search
{
  "from": 0,
  "size": 20,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "_source": {
    "includes": [
      "topLevelMessage"
    ]
  },
  "query": {
    "nested": {
      "_name": "named_query",
      "boost": 1.1,
      "query": {
        "multi_match": {
          "fields": [
            "perguntasRespostas.message"
          ]
        }
      },
      "path": "perguntasRespostas",
      "inner_hits": {
        "explain": true
      },
      "ignore_unmapped": true
    }
  }
}

Вам нужно проверить, является ли этот запрос допустимым для Elasticsearch.

...