代码之家  ›  专栏  ›  技术社区  ›  Anders Gulbæk

如何使用ElasticSearch仅返回属性子集

  •  2
  • Anders Gulbæk  · 技术社区  · 10 年前

    假设我启动了一个ElasticSearch并运行了一个Blog对象。

     public class Blog
     {
         [ElasticProperty(Name = "guid", Index = FieldIndexOption.NotAnalyzed, Type = FieldType.String)]
         public Guid? Guid { get; set; }
    
         [ElasticProperty(Name = "title", Index = FieldIndexOption.Analyzed, Type = FieldType.String)]
        public string Title { get; set; } = "";
    
         [ElasticProperty(Name = "body", Index = FieldIndexOption.Analyzed, Type = FieldType.String)]
         public string Body { get; set; } = "";
    
         [ElasticProperty(Name = "publishedDate", Index = FieldIndexOption.Analyzed, Type = FieldType.Date)]
         public DateTime PublishedDate { get; set; }
    }
    

    现在我只想将属性的子集返回到一个新类中

     public class BlogListItem
     {
           public static Expression<Func<Blog, object>> Selector = e => new BlogListItem
            {
                Title =  e.Title,
                PublishedDate = e.PublishedDate,
            };
    
            public string Title { get; set; }
            public DateTime PublishedDate { get; set; }
     }
    

    通常我使用Entity Framework,在那里我会编写一个类似于BlogListItem类的Selector,但我发现很难在ElasticSearch和NEST中找到任何关于这样做的信息

    var res = elastic.Search<Blog>(s => s
               .From(0)
               .Size(3)
               .Index(blogIndex)
               .Query(q => q.MatchAll())
               .Sort(o => o.OnField(p => p.PublishedDate))
               .Fields(BlogListItem.Selector)
               );
    
      var result = res.Hits.Select(e => e.Source).ToList();
    

    这将返回正确的命中数,但源为空,我无法找到返回的属性。

    解决方案1 我找到了一个替代解决方案,但如果这是一个好的解决方案,我希望得到输入。

    var res2 = elastic.Search<Blog, BlogListItem>(s => s
                 .From(0)
                 .Size(3)
                 .Index(blogIndex)
                 .Query(q => q.MatchAll())
                 .Sort(o => o.OnField(p => p.PublishedDate))
                 );
    
    List<BlogListItem> resultList = res2.Hits.Select(hit => hit.Source).ToList();
    

    这给了我返回的正确对象,但我对映射没有任何控制,我不确定它是否返回所有属性,然后进行映射。

    解决方案2.5 在这个解决方案中,我用一个新的选择器更新了我的BlogListItem。

        public class BlogListItem
        {
            public static SearchSourceDescriptor<Blog> Selector(SearchSourceDescriptor<Blog> sr)
            {
                return sr.Include(fi => fi.Add(f => f.Title));
            }
    
            [ElasticProperty(Name = "title")]        
            public string TitleNewName { get; set; }
            public DateTime PublishedDate { get; set; }
        }
    

    然后我的弹性搜索码

    var res3 = elastic.Search<Blog, BlogListItem>(s => s
                    .From(0)
                    .Size(3)
                    .Index(blogIndex)
                    .Query(q => q.MatchAll())
                    .Sort(o => o.OnField(p => p.PublishedDate))                   
                    .Source(BlogListItem.Selector)
                    );
    
                List<BlogListItem> resultList = res3.Hits.Select(hit => hit.Source).ToList();
    

    现在,这限制了返回的属性,因此我只获得Title,PublishedDate为空,我知道可以控制映射,这要感谢

    [ElasticProperty(Name=“title”)]

    仍然需要验证这是否是使用ElasticSearch的正确方式。

    这将生成以下Json

    {
      "from": 0,
      "size": 3,
      "sort": [
        {
          "publishedDate": {}
        }
      ],
      "_source": {
        "include": [
          "title"      
        ]
      },
      "query": {
        "match_all": {}
      }
    }
    
    1 回复  |  直到 10 年前
        1
  •  1
  •   Community Mohan Dere    9 年前

    您的代码存在一些问题。

    使用 .Fields(BlogListItem.Selector) 返回一个名为“publishedDate.title”的字段,当然这是错误的。我不知道如何使用 Expression 提到字段的语法,所以我不会尝试修复它。我通过打印请求JSON发现了这个错误。看看 my answer 了解如何通过打印请求JSON来调试Nest查询。也许你可以修复 表示 使用此技巧自行语法:)

    我修复了 Fields() 使用我最熟悉的语法:

    .Fields(f => f
        .Add(t => t.Title)
        .Add(t => t.PublishedDate)
    

    即使有了这个修复,您也会发现源代码是 null 。我们来讨论下一个问题。如果您提供 "fields" 搜索请求中的选项, "_source" 将不会出现在响应命中中。这是Elasticsearch的行为,与Nest无关。在这种情况下,你必须依赖 Fields.FieldValuesDictionary 而不是 Source :

    var result = res.Hits.Select(e => e.Fields.FieldValuesDictionary).ToList();
    

    然后你可以建立 BlogListItem 对象。