我有一个看起来像这样的ElasticSearch索引:
{
"mappings": {
"article": {
"properties": {
"title": { "type": "string" },
"tags": {
"type": "keyword"
},
}
}
}
Run Code Online (Sandbox Code Playgroud)
和看起来像这样的数据:
{ "title": "Something about Dogs", "tags": ["articles", "dogs"] },
{ "title": "Something about Cats", "tags": ["articles", "cats"] },
{ "title": "Something about Dog Food", "tags": ["articles", "dogs", "dogfood"] }
Run Code Online (Sandbox Code Playgroud)
如果我搜索dog,我会得到第一个和第三个文件,正如我所期望的那样.而且我可以按照自己喜欢的方式对搜索文档进行加权(实际上,我正在使用一个function_score查询来衡量一堆与此问题无关的字段).
什么我喜欢做的排序是tags场让最相关的标签首先返回,而不会影响文件本身的排序顺序.所以我希望得到这样的结果:
{ "title": "Something about Dog Food", "tags": ["dogs", "dogfood", "articles"] }
Run Code Online (Sandbox Code Playgroud)
而不是我现在得到的:
{ "title": "Something about Dog Food", "tags": ["articles", "dogs", "dogfood"] }
Run Code Online (Sandbox Code Playgroud)
_source鉴于其"匹配"功能,您无法对文档(您的标记数组)进行排序.一种方法是使用嵌套字段,并inner_hits允许您对匹配的嵌套字段进行排序.
我的建议是tags在一个nested领域进行改造(我选择keyword那里只是简单,但你也可以text和你选择的分析仪):
PUT test
{
"mappings": {
"article": {
"properties": {
"title": {
"type": "string"
},
"tags": {
"type": "nested",
"properties": {
"value": {
"type": "keyword"
}
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
并使用这种查询:
GET test/_search
{
"_source": {
"exclude": "tags"
},
"query": {
"bool": {
"must": [
{
"match": {
"title": "dogs"
}
},
{
"nested": {
"path": "tags",
"query": {
"bool": {
"should": [
{
"match_all": {}
},
{
"match": {
"tags.value": "dogs"
}
}
]
}
},
"inner_hits": {
"sort": {
"_score": "desc"
}
}
}
}
]
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您尝试匹配标记的嵌套字段值,则尝试在标题上匹配.然后,使用inner_hits排序,您可以实际根据内部评分对嵌套值进行排序.
@ Val的建议非常好,但只要你的"相关标签"你只需要一个简单的文本匹配作为子串(i1.indexOf(params.search))就可以了.他的解决方案的最大优势是您不必更改映射.
我的解决方案的最大优势是您实际上使用Elasticsearch真正的搜索功能来确定"相关"标签.但缺点是你需要nested字段而不是常规的简单keyword.
您从搜索电话中获得的是源文档。响应中的文档以与索引它们时完全相同的形式返回,这意味着如果您索引["articles", "dogs", "dogfood"],您将始终以未更改的形式获得该数组。
解决这个问题的一种方法是声明一个script_field应用一个小脚本来对数组进行排序并返回该排序的结果。
该脚本所做的只是将包含搜索词的词移动到列表的前面
{
"_source": ["title"],
"query" : {
"match_all": {}
},
"script_fields" : {
"sorted_tags" : {
"script" : {
"lang": "painless",
"source": "return params._source.tags.stream().sorted((i1, i2) -> i1.indexOf(params.search) > -1 ? -1 : 1).collect(Collectors.toList())",
"params" : {
"search": "dog"
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将返回类似这样的内容,因为您可以看到该sorted_tags数组包含您期望的术语。
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "tests",
"_type": "article",
"_id": "1",
"_score": 1,
"_source": {
"title": "Something about Dog Food"
},
"fields": {
"sorted_tags": [
"dogfood",
"dogs",
"articles"
]
}
}
]
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
423 次 |
| 最近记录: |