NEST Api SearchAfter 在 NEST 中返回 null 但在 Kibana 中有效

Posted

技术标签:

【中文标题】NEST Api SearchAfter 在 NEST 中返回 null 但在 Kibana 中有效【英文标题】:NEST Api SearchAfter return null in NEST but works in Kibana 【发布时间】:2018-03-26 10:52:37 【问题描述】:

我们在我们的应用程序中仅使用弹性搜索来进行文档搜索,因此我们没有任何一位专家。我能够成功使用TermQuerySimpleQueryStringQueryMatchPhraseQuery。但我在文档中发现使用FromSize 进行分页不利于生产,建议使用搜索后。

但我的实现返回null。正如 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 是映射返回结果的类。

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

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


更新

查看答案后,我更新了我的代码,尽管获得的查询确实有效。它在 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 的响应确实说成功,但没有返回任何结果。

结果在 Kibana 中返回 查询状态成功 但是…… NEST 中返回的总数为 0 在kibana中排序值为null我用TrackScores = true解决了这个问题

这里是调试信息:

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":[]

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


更新 2:

控制器中的代码:

连接字符串:

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 &lt;my index name&gt;/_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

我认为问题可能出在某个地方?该类是通过在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
                ;

【问题讨论】:

您是说 exact same 查询在 Kibana 中有效,但在 NEST 中无效? 是的,kibana 给出结果,但 NEST 没有。调试信息来自 NEST 您能否更新您的问题以提供一个简洁、可重复的示例?我不认为它们可以是 Kibana 和 NEST 中的完全相同查询。您可以从 Kibana 获取 JSON 并将其传递给低级客户端搜索方法以进行验证 我会更新剩余的代码和我的映射类。但是关于你的第二个问题,我正在接受 NEST 构建的精确查询,然后在控制台中在 GET ExtractIndex/_Search 之后通过它并给出了结果。 没问题,很高兴你把它整理好了。我强烈建议阅读我上面链接到的文档,因为那里有很多有用的信息:) 【参考方案1】:

deep pagination 不建议使用 from/size,因为对于一个 deep page,需要从所有分片中获取大量文档,只能丢弃当最终返回一个整体有序的结果集时。此操作是 Elasticsearch 的分布式特性所固有的,并且在许多与深度分页相关的分布式系统中都很常见。

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

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

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

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

它将带你到文档的 github 存储库,以及页面的原始 asciidoc 降价:

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

【讨论】:

你的回答确实帮助了我前进,但我又遇到了一个小问题,请你看看更新部分并指导我。 @Russ Cam 我在两个示例中都有编译错误:"Project" doesn't contain a definition for "First"(Fluent DSL 或对象初始化程序)。另外,在对象初始化器中我也有错误:The non-generic type "Field" cannot be used with type arguments。我错过了什么? @abdul qayyum 你成功了吗?

以上是关于NEST Api SearchAfter 在 NEST 中返回 null 但在 Kibana 中有效的主要内容,如果未能解决你的问题,请参考以下文章

使用nest.js在AWS Lambda中获取Cognito数据(即requestContext)

如何在 Nest API iOS 中成功注销后重新加载登录页面

在 Nest.js 中,如何在我的 API 响应中提供与我的 JSON 对象捆绑在一起的静态内容文件

在 Echo Nest API 中通过 Spotify ID 查询

用Lucene searchafter分页,怎样排序

Nest.js 中特定路由上的 WebSockets