如何使用 ElasticSearch 仅 return 个属性子集
How to only return a subset of properties with ElasticSearch
假设我启动了 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; }
}
现在我只想return属性的一个子集变成一个新的class
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 class 中编写一个选择器,但我发现很难在 ElasticSearch 中使用 NEST[= 找到关于这样做的任何信息19=]
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();
这 return 是正确的点击数,但是来源为空,我不知道在哪里可以找到 returned 属性。
解决方案 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();
这给了我正确的对象 returned,但我对映射没有任何控制,我不确定它是否 return 所有属性然后进行映射.
解决方案 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; }
}
然后是我的elasticSearch代码
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();
现在这限制了属性 returned 所以我只得到 Title 并且 PublishedDate 为 null 并且我知道由于
可以控制映射
[ElasticProperty(Name = "title")]
仍然需要验证这是否是使用 ElasticSearch 的正确方法。
这会产生以下结果 Json
{
"from": 0,
"size": 3,
"sort": [
{
"publishedDate": {}
}
],
"_source": {
"include": [
"title"
]
},
"query": {
"match_all": {}
}
}
您的代码存在一些问题。
使用 .Fields(BlogListItem.Selector)
returns 一个名为 "publishedDate.title" 的字段,这当然是错误的。我不确定如何使用 Expression
语法来提及字段,所以我不会尝试修复它。我通过打印请求 JSON 发现了这个错误。查看 上关于 SO 的另一个问题,了解如何通过打印请求 JSON 来调试 Nest 查询。也许你可以使用这个技巧自己修复 Expression
语法 :)
我使用我最熟悉的语法修复了 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
个对象。
假设我启动了 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; }
}
现在我只想return属性的一个子集变成一个新的class
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 class 中编写一个选择器,但我发现很难在 ElasticSearch 中使用 NEST[= 找到关于这样做的任何信息19=]
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();
这 return 是正确的点击数,但是来源为空,我不知道在哪里可以找到 returned 属性。
解决方案 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();
这给了我正确的对象 returned,但我对映射没有任何控制,我不确定它是否 return 所有属性然后进行映射.
解决方案 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; }
}
然后是我的elasticSearch代码
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();
现在这限制了属性 returned 所以我只得到 Title 并且 PublishedDate 为 null 并且我知道由于
可以控制映射[ElasticProperty(Name = "title")]
仍然需要验证这是否是使用 ElasticSearch 的正确方法。
这会产生以下结果 Json
{
"from": 0,
"size": 3,
"sort": [
{
"publishedDate": {}
}
],
"_source": {
"include": [
"title"
]
},
"query": {
"match_all": {}
}
}
您的代码存在一些问题。
使用 .Fields(BlogListItem.Selector)
returns 一个名为 "publishedDate.title" 的字段,这当然是错误的。我不确定如何使用 Expression
语法来提及字段,所以我不会尝试修复它。我通过打印请求 JSON 发现了这个错误。查看 Expression
语法 :)
我使用我最熟悉的语法修复了 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
个对象。