elasticsearch - 如何使用 elasticsearch 过滤查询结果
问题描述
我正在尝试创建一个为用户和组提供预先输入自动完成建议的组件。我正在使用弹性搜索 6.5.3。我创建了一个索引,其中包含我要搜索的字段和 3 个要按 (isGroup、isUser、organizationId) 过滤的附加字段。在某些情况下,我想使用这个组件来搜索所有用户和组,有时只是用户或组,或者只是属于特定组织的用户。我计划根据具体的用例提供一个过滤器和搜索词。我正在使用nest 进行搜索,但我不知道该怎么做。是否有可能做到这一点,如果可以,怎么做?我是否为此走错了路?我主要按照本指南创建分析器和东西。如果有帮助,我可以发布我的索引,但它有点长。
这是返回的两个项目的搜索。
return client.Search<UserGroupDocument>(s => s
.Query(q=>q
.QueryString(qs=>qs.Query("adm"))
)
);
{
"_index": "users_and_groups_autocomplete_index",
"_type": "usergroupdocument",
"_id": "c54956ab-c50e-481c-b093-f9855cc74480",
"_score": 2.2962174,
"_source": {
"id": "c54956ab-c50e-481c-b093-f9855cc74480",
"isUser": true,
"isGroup": false,
"name": "admin",
"email": "admin@snapshotdesign.com",
"organizationId": 2
}
},
{
"_index": "users_and_groups_autocomplete_index",
"_type": "usergroupdocument",
"_id": "80f98d24-39e3-475d-9cb6-8f16ca472525",
"_score": 0.8630463,
"_source": {
"id": "80f98d24-39e3-475d-9cb6-8f16ca472525",
"isUser": false,
"isGroup": true,
"name": "new Group",
"users": [
{
"name": "Test User 1",
"email": "test@example.com"
},
{
"name": "admin",
"email": "admin@snapshotdesign.com"
}
],
"organizationId": 0
}
},
因此,根据我在哪里使用此组件,我可能希望所有这些返回,只是用户、组或组织 2 中的用户。
这是我的 UserGroupDocument 类
public class UserGroupDocument
{
public string Id { get; set; }
public bool IsUser { get; set; }
public bool IsGroup { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<User> Users { get; set; }
public long OrganizationId { get; set; }
}
和用户类
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}
根据下面 Russ Cam 的回答,我更改了 Must 语句,如下所示。这给了我我想要的过滤,但不是预输入功能。在开始匹配之前,我仍然需要输入整个单词。
.Must(mu => mu
.QueryString(mmp => mmp
.Query(searchTerms)
.Fields(f => f
.Field(ff => ff.Name)
.Field(ff => ff.Users.Suffix("name"))
)
)
)
这是我正在使用的索引。
{
"users_and_groups_autocomplete_index": {
"aliases": {},
"mappings": {
"usergroupdocument": {
"properties": {
"email": {
"type": "text",
"fields": {
"autocomplete": {
"type": "text",
"analyzer": "autocomplete"
}
}
},
"id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"isGroup": {
"type": "boolean"
},
"isUser": {
"type": "boolean"
},
"name": {
"type": "text",
"fields": {
"autocomplete": {
"type": "text",
"analyzer": "autocomplete"
}
}
},
"organizationId": {
"type": "long"
},
"users": {
"properties": {
"email": {
"type": "text",
"fields": {
"autocomplete": {
"type": "text",
"analyzer": "autocomplete"
}
}
},
"name": {
"type": "text",
"fields": {
"autocomplete": {
"type": "text",
"analyzer": "autocomplete"
}
}
}
}
}
}
}
},
"settings": {
"index": {
"number_of_shards": "5",
"provided_name": "users_and_groups_autocomplete_index",
"creation_date": "1548363729311",
"analysis": {
"analyzer": {
"autocomplete": {
"filter": [
"lowercase"
],
"type": "custom",
"tokenizer": "autocomplete"
}
},
"tokenizer": {
"autocomplete": {
"token_chars": [
"digit",
"letter"
],
"min_gram": "1",
"type": "edge_ngram",
"max_gram": "20"
}
}
},
"number_of_replicas": "1",
"uuid": "Vxv-y58qQTG8Uh76Doi_dA",
"version": {
"created": "6050399"
}
}
}
}
}
解决方案
您正在寻找一种将多个查询组合在一起的方法:
- 查询搜索词
- 查询
isGroup
- 查询
isUser
- 查询
organizationId
并使用这些组合执行搜索。这就是像查询这样的复合查询bool
出现的地方。给定以下 POCO
public class UserGroupDocument
{
public string Name { get; set; }
public bool IsGroup { get; set; }
public bool IsUser { get; set; }
public string OrganizationId { get; set; }
}
我们可以从
private static void Main()
{
var defaultIndex = "default-index";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(settings);
var isUser = true;
var isGroup = true;
var organizationId = "organizationId";
var searchResponse = client.Search<UserGroupDocument>(x => x
.Index(defaultIndex)
.Query(q => q
.Bool(b => b
.Must(mu => mu
.QueryString(mmp => mmp
.Query("some admin")
.Fields(f => f
.Field(ff => ff.Name)
)
)
)
.Filter(fi =>
{
if (isUser)
{
return fi
.Term(f => f.IsUser, true);
}
return null;
}, fi =>
{
if (isGroup)
{
return fi
.Term(f => f.IsGroup, true);
}
return null;
}, fi => fi
.Term(f => f.OrganizationId, organizationId)
)
)
)
);
}
这将产生以下查询
POST http://localhost:9200/default-index/usergroupdocument/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"isUser": {
"value": true
}
}
},
{
"term": {
"isGroup": {
"value": true
}
}
},
{
"term": {
"organizationId": {
"value": "organizationId"
}
}
}
],
"must": [
{
"query_string": {
"fields": [
"name"
],
"query": "some admin"
}
}
]
}
}
}
如果
isUser
即false
,字段上的term
查询过滤器isUser
不会包含在搜索查询中isGroup
即false
,字段上的term
查询过滤器isGroup
不会包含在搜索查询中organizationId
isnull
或空字符串,则term
查询过滤器organizationId
不会包含在搜索查询中。
现在,我们可以更进一步,制作isGroup
可isUser
空的布尔值 ( bool?
)。然后,当其中一个的值为 时null
,相应的term
查询过滤器将不会包含在发送到 Elasticsearch 的搜索查询中。这利用了 Nest 中称为无条件查询的功能,该功能旨在使编写更复杂的查询更容易。此外,我们可以在查询上使用运算符重载,以使编写bool
查询更容易。这一切都意味着我们可以将查询细化为
bool? isUser = true;
bool? isGroup = true;
var organizationId = "organizationId";
var searchResponse = client.Search<UserGroupDocument>(x => x
.Index(defaultIndex)
.Query(q => q
.QueryString(mmp => mmp
.Query("some admin")
.Fields(f => f
.Field(ff => ff.Name)
)
) && +q
.Term(f => f.IsUser, isUser) && +q
.Term(f => f.IsGroup, isGroup) && +q
.Term(f => f.OrganizationId, organizationId)
)
);
推荐阅读
- ruby-on-rails - Rails 6 表单中缺少参数
- sql - 通过连接表在原始 sql 中查找
- python - Python,如何将现有的父类对象转换为子类对象
- javascript - 谷歌地图移动多个标记Javascript
- python - 如何打破无限的 Python 循环?
- php - PHP计算字符串中数组项的实例
- android - 如何强制 Android 对话框中的文本向左对齐
- swift - 如何使用不同的字符串将图像上传到 Firebase?
- android - android.content.ActivityNotFoundException:无法找到显式活动类 Android Studio Kotlin 错误
- c++ - 初始化模板内的变量