如何使用 ElasticSearch 的 NEST .net 客户端库创建查询以匹配子集合属性?
How to create query to match child collection attributes using NEST .net client library for ElasticSearch?
我在 ElasticSearch 7.3 中的 http://xyzserver:9200/mydocs/brands 有以下 4 个文档
每个文件代表一个品牌的一些细节。一个品牌可以与多个组相关联,并且可以对 0 个或多个组有效。
更新 1:这是文档映射
{
"mydocs": {
"mappings": {
"properties": {
"Groups": {
"properties": {
"GroupId": {
"type": "long"
},
"GroupName": {
"type": "text"
},
"IsActive": {
"type": "boolean"
}
}
},
"Id": {
"type": "long"
},
"Name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
我加载了 4 个文档。
{
Id: 100,
Name: 'Diet Coke',
Groups:
[{
GroupId: 200,
GroupName: 'US East',
IsActive: true
},
{
GroupId: 201,
GroupName: 'US West',
IsActive: true
},
{
GroupId: 202,
GroupName: 'US South',
IsActive: false
}
]
}
{
Id: 110,
Name: 'Coke',
Groups:
[{
GroupId: 200,
GroupName: 'US East',
IsActive: false
},
{
GroupId: 201,
GroupName: 'US West',
IsActive: true
},
{
GroupId: 202,
GroupName: 'US South',
IsActive: true
}
]
}
{
Id: 120,
Name: 'Coke with Lime',
Groups:
[{
GroupId: 200,
GroupName: 'US East',
IsActive: true
},
{
GroupId: 201,
GroupName: 'US West',
IsActive: true
},
{
GroupId: 202,
GroupName: 'US South',
IsActive: true
}
]
}
{
Id: 130,
Name: 'Cola',
Groups:
[{
GroupId: 300,
GroupName: 'Europe East',
IsActive: true
},
{
GroupId: 400,
GroupName: 'Mexico',
IsActive: true
},
{
GroupId: 410,
GroupName: 'Brazile',
IsActive: true
}
]
}
我正在搜索 "Coke",它是“200 - US East Group”和“201 - US West Group”两个组的 "Active"。假设我有一个搜索条件类型
public class BrandSearchCriteria {
public string Keyword {get; set;}
public IEnumerable<int> GroupIds {get; set;} = new List<int>();
public bool? IsActive {get; set;} //true if looking for only active items, false if looking for inactive items, null if looking for both
}
searchCriteria = new BrandSearchCriteria
{
Keyword = "Coke",
GroupIds = new List<int> { 200, 201 },
IsActive = true
}
如何使用 NEST 库创建查询?这是我目前所拥有的
QueryContainerDescriptor<Brand> queryDescriptor = new QueryContainerDescriptor<Brand>();
queryDescriptor.Bool(b =>
b.Must(q =>
q.Match(m => m.Field(f => f.Name).Fuzziness(Fuzziness.Auto).Query(searchCriteria.KeyWord) &&
q.Terms(t => t.Field("Groups.GroupId").Terms<int>(searchCriteria.GroupIds)) &&
q.Term(t => t.Field("Groups.IsActive").Value(searchCriteria.IsActive.ToString()))
)
);
我假设只取回 ID 为 100(健怡可乐)和 120(酸橙可乐)的两个文档,因为这两个文档是两个组“200 - US East Group”&&“201”中仅有的两个活动文件- 美西集团。
但上面的查询是给我返回 3 个文档 100(健怡可乐)、110(可口可乐)、120(可口可乐加酸橙)。即使文档 110(可口可乐)对于组“201 - US West Group”无效,它仍会包含在结果中。
我刚开始学习 NEST 库的使用,不知道如何制定查询来检索结果。任何帮助将不胜感激。
首先,我认为您需要更改映射。具体来说 Groups
应该嵌套
{
"mappings": {
"properties": {
"Groups": {
"type": "nested",
"properties": {
"GroupId": {
"type": "long"
},
"GroupName": {
"type": "text"
},
"IsActive": {
"type": "boolean"
}
}
},
"Id": {
"type": "long"
},
"Name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
那么基于您的嵌套代码如下所示:
// preparing the query
var groupIds = new[] { 200, 201 };
Func<QueryContainerDescriptor<Brand>, int, QueryContainer> nestedQuery = (q, groupId) => q.Nested(n => n.Path("Groups").Query(nq => nq.Bool(nb => nb.Filter(
fq => fq.Term(t => t.Field("Groups.GroupId").Value(groupId)),
fq => fq.Term(t => t.Field("Groups.IsActive").Value(true))))
)
);
var query = groupIds.Select(groupId => nestedQuery(new QueryContainerDescriptor<Brand>(), groupId)).ToList();
query.Add(new QueryContainerDescriptor<Brand>().Match(m => m.Field("Name").Fuzziness(Fuzziness.Auto).Query("coke")));
var queryDescriptor = new QueryContainerDescriptor<Brand>();
queryDescriptor.Bool(b => b.Must(query.ToArray()));
几点建议:
在 Field
等方法中使用 Expression
而不是字符串
ES 端的 boolean
类型在 C# 上是 bool
。不确定为什么要将其转换为字符串。
在不需要评分的时候使用过滤器,基本上是yes/no答案。
我会在这里使用无痛脚本。会看起来更干净
我在 ElasticSearch 7.3 中的 http://xyzserver:9200/mydocs/brands 有以下 4 个文档 每个文件代表一个品牌的一些细节。一个品牌可以与多个组相关联,并且可以对 0 个或多个组有效。
更新 1:这是文档映射
{
"mydocs": {
"mappings": {
"properties": {
"Groups": {
"properties": {
"GroupId": {
"type": "long"
},
"GroupName": {
"type": "text"
},
"IsActive": {
"type": "boolean"
}
}
},
"Id": {
"type": "long"
},
"Name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
我加载了 4 个文档。
{
Id: 100,
Name: 'Diet Coke',
Groups:
[{
GroupId: 200,
GroupName: 'US East',
IsActive: true
},
{
GroupId: 201,
GroupName: 'US West',
IsActive: true
},
{
GroupId: 202,
GroupName: 'US South',
IsActive: false
}
]
}
{
Id: 110,
Name: 'Coke',
Groups:
[{
GroupId: 200,
GroupName: 'US East',
IsActive: false
},
{
GroupId: 201,
GroupName: 'US West',
IsActive: true
},
{
GroupId: 202,
GroupName: 'US South',
IsActive: true
}
]
}
{
Id: 120,
Name: 'Coke with Lime',
Groups:
[{
GroupId: 200,
GroupName: 'US East',
IsActive: true
},
{
GroupId: 201,
GroupName: 'US West',
IsActive: true
},
{
GroupId: 202,
GroupName: 'US South',
IsActive: true
}
]
}
{
Id: 130,
Name: 'Cola',
Groups:
[{
GroupId: 300,
GroupName: 'Europe East',
IsActive: true
},
{
GroupId: 400,
GroupName: 'Mexico',
IsActive: true
},
{
GroupId: 410,
GroupName: 'Brazile',
IsActive: true
}
]
}
我正在搜索 "Coke",它是“200 - US East Group”和“201 - US West Group”两个组的 "Active"。假设我有一个搜索条件类型
public class BrandSearchCriteria {
public string Keyword {get; set;}
public IEnumerable<int> GroupIds {get; set;} = new List<int>();
public bool? IsActive {get; set;} //true if looking for only active items, false if looking for inactive items, null if looking for both
}
searchCriteria = new BrandSearchCriteria
{
Keyword = "Coke",
GroupIds = new List<int> { 200, 201 },
IsActive = true
}
如何使用 NEST 库创建查询?这是我目前所拥有的
QueryContainerDescriptor<Brand> queryDescriptor = new QueryContainerDescriptor<Brand>();
queryDescriptor.Bool(b =>
b.Must(q =>
q.Match(m => m.Field(f => f.Name).Fuzziness(Fuzziness.Auto).Query(searchCriteria.KeyWord) &&
q.Terms(t => t.Field("Groups.GroupId").Terms<int>(searchCriteria.GroupIds)) &&
q.Term(t => t.Field("Groups.IsActive").Value(searchCriteria.IsActive.ToString()))
)
);
我假设只取回 ID 为 100(健怡可乐)和 120(酸橙可乐)的两个文档,因为这两个文档是两个组“200 - US East Group”&&“201”中仅有的两个活动文件- 美西集团。
但上面的查询是给我返回 3 个文档 100(健怡可乐)、110(可口可乐)、120(可口可乐加酸橙)。即使文档 110(可口可乐)对于组“201 - US West Group”无效,它仍会包含在结果中。
我刚开始学习 NEST 库的使用,不知道如何制定查询来检索结果。任何帮助将不胜感激。
首先,我认为您需要更改映射。具体来说 Groups
应该嵌套
{
"mappings": {
"properties": {
"Groups": {
"type": "nested",
"properties": {
"GroupId": {
"type": "long"
},
"GroupName": {
"type": "text"
},
"IsActive": {
"type": "boolean"
}
}
},
"Id": {
"type": "long"
},
"Name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
那么基于您的嵌套代码如下所示:
// preparing the query
var groupIds = new[] { 200, 201 };
Func<QueryContainerDescriptor<Brand>, int, QueryContainer> nestedQuery = (q, groupId) => q.Nested(n => n.Path("Groups").Query(nq => nq.Bool(nb => nb.Filter(
fq => fq.Term(t => t.Field("Groups.GroupId").Value(groupId)),
fq => fq.Term(t => t.Field("Groups.IsActive").Value(true))))
)
);
var query = groupIds.Select(groupId => nestedQuery(new QueryContainerDescriptor<Brand>(), groupId)).ToList();
query.Add(new QueryContainerDescriptor<Brand>().Match(m => m.Field("Name").Fuzziness(Fuzziness.Auto).Query("coke")));
var queryDescriptor = new QueryContainerDescriptor<Brand>();
queryDescriptor.Bool(b => b.Must(query.ToArray()));
几点建议:
在
Field
等方法中使用 boolean
类型在 C# 上是bool
。不确定为什么要将其转换为字符串。在不需要评分的时候使用过滤器,基本上是yes/no答案。
我会在这里使用无痛脚本。会看起来更干净
Expression
而不是字符串
ES 端的