NEST Api Search在NEST中返回null但在Kibana中工作

时间:2018-03-26 10:52:38

标签: c# json elasticsearch nest

我们在应用程序中使用弹性搜索仅用于文档搜索,因此我们没有任何一位专家。我成功地使用了TermQuerySimpleQueryStringQueryMatchPhraseQuery。但我在文档中发现使用From& Size分页不适合制作,建议使用Search After。

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

我的代码如下所示:

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仅用于测试以及_id中的硬代码SearchAfter值。

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中的排序值为空我使用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 <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

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

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

Elasticsearch documentation on elastic.co

将带您到文档的github存储库,页面的原始asciidoc markdown:

Asciidoc source for documentation

在该页面中将链接回原始NEST源代码,从中生成asciidoc。在这种情况下,原始文件为SearchAfterUsageTests.cs in the 6.x branch