NEST Api SearchAfter return 在 NEST 中为 null 但在 Kibana 中有效

NEST Api SearchAfter return null in NEST but works in Kibana

我们仅在应用程序中使用弹性搜索来进行文档搜索,因此我们没有任何专家。我能够成功使用 TermQuerySimpleQueryStringQueryMatchPhraseQuery。但我在文档中发现,使用 From & Size 进行分页对生产环境不利,建议使用 Search After。

但是我的实现returnnull。正如 Nest API Object Initializer 语法 in docs here 中所示,<Project> 参数中的内容令我感到困惑。

我的代码如下所示:

var request = new SearchRequest<ElasticSearchJsonObject._Source>
 {
    //Sort = new List<ISort>
    //{
    //    new SortField { Field = Field<ElasticSearchJsonObject>(p=>)}
    //},
    SearchAfter = new List<object> {

    },                    
    Size = 20,
    Query = query
  };                               

现实是我不明白这一点。在这里 ElasticSearchJsonObject._Source 是映射 returned 结果的 class。

我的文档是简单的文本文档,我只想根据分数对文档进行排序,因此文档 ID 不相关。

SO 上已经有这样的问题,但我怎么找不到。


更新

查看答案后,我更新了我的代码,尽管获得的查询确实有效。它 return 导致 kibana 而不是 NEST。

这是新更新的代码:

var request = new SearchRequest<ElasticSearchJsonObject.Rootobject>
            {
                Sort = new List<ISort>
                {
                    new SortField { Field = "_id", Order = SortOrder.Descending}
                },
                SearchAfter = new List<object> {
                   "0fc3ccb625f5d95b973ce1462b9f7"
                },                    
                Size = 1,
                Query = query
            };

在这里我使用 size=1 只是为了测试以及 SearchAfter 中的硬编码 _id 值。

NEST 生成的查询是:

{
  "size": 1,
  "sort": [
    {
      "_id": {
        "order": "desc"
      }
    }
  ],
  "search_after": [
    "0fc3ccb625f5d95b973ce1462b9f7"
  ],
  "query": {
    "match": {
      "content": {
        "query": "lahore",
        "fuzziness": "AUTO",
        "prefix_length": 3,
        "max_expansions": 10
      }
    }
  }
}

来自 ES 的响应确实说成功但没有结果 returned。

调试信息如下:

Valid NEST response built from a successful low level call on POST: /extract/_source/_search?typed_keys=true
# Audit trail of this API call:
 - [1] HealthyResponse: Node: http://localhost:9200/ Took: 00:00:00.1002662
# Request:
{"size":1,"sort":[{"_id":{"order":"desc"}}],"search_after":["0fc3ccb625f5d95b973ce1462b9f7"],"query":{"match":{"content":{"query":"lahore","fuzziness":"AUTO","prefix_length":3,"max_expansions":10}}}}
# Response:
{"took":3,"timed_out":false,"_shards":{"total":5,"successful":5,"skipped":0,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}

所以请告诉我哪里错了,可能是什么问题以及如何解决它。


更新二:

控制器中的代码:

连接字符串:

var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node);
settings.DisableDirectStreaming();
settings.DefaultIndex("extract");
var client = new ElasticClient(settings);

查询:

var query = (dynamic)null;
query = new MatchQuery
 {
    Field = "content",
    Query = content,
    Fuzziness = Fuzziness.Auto,
    PrefixLength = 3,
    MaxExpansions = 10
   };

查询生成器

var request = new SearchRequest<ElasticSearchJsonObject.Rootobject>
            {
                Sort = new List<ISort>
                {
                    new SortField { Field = "_id", Order = SortOrder.Descending}
                },
                SearchAfter = new List<object> {
                   documentid //sent as parameter
                },                    
                Size = 1, //for testing 1 other wise 10
                TrackScores = true,
                Query = query
            };

JSON查询 我使用此代码来获取上面发布的查询。然后使用 GET <my index name>/_Search 将此查询传递给 kibana 并在那里工作

var stream = new System.IO.MemoryStream();
client.SourceSerializer.Serialize(request, stream);
var jsonQuery = System.Text.Encoding.UTF8.GetString(stream.ToArray());

ES 响应

string responseJson = "";
                ElasticSearchJsonObject.Rootobject response = new ElasticSearchJsonObject.Rootobject();
                var res = client.Search<object>(request);
                if (res.ApiCall.ResponseBodyInBytes != null)
                {
                    responseJson = System.Text.Encoding.UTF8.GetString(res.ApiCall.ResponseBodyInBytes);
                    try
                    {
                        response = JsonConvert.DeserializeObject<ElasticSearchJsonObject.Rootobject>(responseJson);
                    }
                    catch (Exception)
                    {
                        var model1 = new LoginSignUpViewModel();
                        return PartialView("_NoResultPage", model1);
                    }
                }

这就是问题所在。以上调试信息来自 response

ElasticSearchJsonObject

我怎么觉得问题可能出在这里? class 是通过在 Search 请求中获取 NEST 的响应生成的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ESAPI
{
    public class ElasticSearchJsonObject
    {
        public class Rootobject
        {
            public int took { get; set; }
            public bool timed_out { get; set; }
            public _Shards _shards { get; set; }
            public Hits hits { get; set; }
        }

        public class _Shards
        {
            public int total { get; set; }
            public int successful { get; set; }
            public int skipped { get; set; }
            public int failed { get; set; }
        }

        public class Hits
        {
            public int total { get; set; }
            public float max_score { get; set; }
            public Hit[] hits { get; set; }
        }

        public class Hit
        {
            public string _index { get; set; }
            public string _type { get; set; }
            public string _id { get; set; }
            public float _score { get; set; }
            public _Source _source { get; set; }
        }

        public class _Source
        {
            public string content { get; set; }
            public Meta meta { get; set; }
            public File file { get; set; }
            public Path path { get; set; }
        }

        public class Meta
        {
            public string title { get; set; }
            public Raw raw { get; set; }
        }

        public class Raw
        {
            public string XParsedBy { get; set; }
            public string Originator { get; set; }
            public string dctitle { get; set; }
            public string ContentEncoding { get; set; }
            public string ContentTypeHint { get; set; }
            public string resourceName { get; set; }
            public string ProgId { get; set; }
            public string title { get; set; }
            public string ContentType { get; set; }
            public string Generator { get; set; }
        }

        public class File
        {
            public string extension { get; set; }
            public string content_type { get; set; }
            public DateTime last_modified { get; set; }
            public DateTime indexing_date { get; set; }
            public int filesize { get; set; }
            public string filename { get; set; }
            public string url { get; set; }
        }

        public class Path
        {
            public string root { get; set; }
            public string _virtual { get; set; }
            public string real { get; set; }
        }
    }
}

我相信这可以用来获得回应。

请注意,在简单搜索的情况下,此代码有效:

所以对于下面的这个查询,我的代码是有效的:

var request = new SearchRequest
                {
                    From = 0,
                    Size = 20,
                    Query = query
                };

不建议将 from/size 用于 深度分页 ,因为 深度页面需要从所有分片中获取大量文档,只有在最终 return 整个有序结果集时才被丢弃。此操作是 Elasticsearch 的分布式特性所固有的,并且在与深度分页相关的许多分布式系统中很常见。

使用 search_after,您可以 分页 以无状态方式转发文档,这需要

  • 来自第一个搜索响应的 return 文档已排序(文档默认按 _score 排序)
  • 将来自一个搜索请求的命中中最后一个文档的排序字段的值作为下一个请求的 "search_after": [] 的值传递。

在 Search After Usage 文档中,搜索请求是按 NumberOfCommits 降序排序,然后按 Name 降序排序。用于每个排序字段的值在 SearchAfter(...) 中传递,并且分别是 Project.First.NumberOfCommitsProject.First.Name 属性的值。这告诉 Elasticsearch return 具有排序字段值的文档,这些字段对应于每个字段的排序约束,并且与请求中提供的值相关。例如,在 NumberOfCommits 上按提供的值 775 降序排序意味着 Elasticsearch 应该只考虑值小于 775 的文档(并对所有排序字段和提供的值执行此操作)。

如果您需要进一步深入了解任何 NEST 文档,请单击页面上的 "EDIT" link:

这将带您进入文档的 github 存储库,其中包含页面的原始 asciidoc markdown:

在该页面内将 link 返回到生成 asciidoc 的原始 NEST 源代码。在这种情况下,原始文件是 SearchAfterUsageTests.cs in the 6.x branch