我正在尝试找到一种使用Elasticsearch查询以句点和连字符分隔的字段的方法。
我有一个这样的(MySQL)数据集(使用SQLAlchemy访问它):
id text tag
====================================
1 some-text A.B.c3
2 more. text A.B-C.c4
3 even more. B.A-32.D-24.f9
首先使用ES进行搜索的主要原因是我想针对text
字段进行查询。那部分很棒!
但是,(我认为)我希望tag
像这样在倒排索引中显示(我可能不会考虑大小写,仅出于说明目的而包括在内):
A.B.c3 1
A.B-C.c4 2
B.A-C2.D-24.f9 3
然后,我要像这样搜索tag
字段:
{ "query": {
"prefix" : { "tag" : "A.B" }
}
}
并使查询返回id
/行/文档1和2。
基本上,我希望查询匹配此真值表中的索引:
"A." = 1, 2
"A-" = 3
如何在开始时同时完成“ A.
”匹配,区分句号和连字符(可能要加倍),并根据相同的分隔符匹配中间短语?
如果可能的话,如果这些匹配出现在tag
字段的开头,我也希望对其进行加权。
我该怎么做,还是Elasticsearch不是适合该工作的工具?看来Elasticsearch对于我在通常分隔的英文文本上进行文本字段比较非常有效,但是基于标签的搜索似乎要困难得多。
更新:看来,当我仅对搜索返回的结果的一部分数据进行索引时,但对整个数据集进行查询时,我得到的点击率就会降低。>
答案 0 :(得分:1)
这可以通过N-Gram标记程序来完成。
根据您所提供的内容,我创建了其对应的映射,文档和示例查询,以为您提供所需的内容。
PUT idtesttag
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "ngram",
"min_gram": 2,
"max_gram": 5
}
}
}
},
"mappings": {
"mydocs": {
"properties": {
"id": {
"type": "long"
},
"text": {
"type": "text",
"analyzer": "my_analyzer"
},
"tag": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
}
这将是什么,如果您有一个带有id = 1
的文档且带有标签A.B
,它将在其反向索引中存储以下字符组。
A. -> 1
.B -> 1
A.B -> 1
因此,如果您的查询包含这三个词中的任何一个,则将返回带有id=1
的文档。
POST idtesttag/mydocs/1
{
"id": 1,
"text": "some-text",
"tag": "A.B.c3"
}
POST idtesttag/mydocs/2
{
"id": 2,
"text": "more. text",
"tag": "A.B-C.c4"
}
POST idtesttag/mydocs/3
{
"id": 3,
"text": "even more.",
"tag": "B.A-32.D-24.f9"
}
POST idtesttag/mydocs/4
{
"id": 3,
"text": "even more.",
"tag": "B.A.B-32.D-24.f9"
}
POST idtesttag/_search
{
"query": {
"match": {
"tag": "A.B"
}
}
}
{
"took": 139,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0.8630463,
"hits": [
{
"_index": "idtesttag",
"_type": "mydocs",
"_id": "1",
"_score": 0.8630463,
"_source": {
"id": 1,
"text": "some-text",
"tag": "A.B.c3"
}
},
{
"_index": "idtesttag",
"_type": "mydocs",
"_id": "2",
"_score": 0.66078395,
"_source": {
"id": 2,
"text": "more. text",
"tag": "A.B-C.c4"
}
},
{
"_index": "idtesttag",
"_type": "mydocs",
"_id": "4",
"_score": 0.46659434,
"_source": {
"id": 3,
"text": "even more.",
"tag": "B.A.B-32.D-24.f9"
}
}
]
}
}
请注意,文档1、2和4在响应中返回。 document 4
是句子中的匹配,而文档1 & 2
则位于开头。
还要注意分数值的显示方式。
现在关于基于hypen
字符的增强,我建议您与Bool一起进行Regex Query with Boosting查询。以下是我想出的示例查询。
请注意,为简单起见,我添加了正则表达式,仅当hypen位于A.B
旁边时,它才会增强。
POST idtesttag/_search
{
"query": {
"bool": {
"must" : {
"match" : { "tag" : "A.B" }
},
"should": [
{
"regexp": {
"tag": {
"value": "A.B-.*",
"boost": 3
}
}
}
]
}
}
}
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 3.660784,
"hits": [
{
"_index": "idtesttag",
"_type": "mydocs",
"_id": "2",
"_score": 3.660784,
"_source": {
"id": 2,
"text": "more. text",
"tag": "A.B-C.c4"
}
},
{
"_index": "idtesttag",
"_type": "mydocs",
"_id": "4",
"_score": 3.4665942,
"_source": {
"id": 3,
"text": "even more.",
"tag": "B.A.B-32.D-24.f9"
}
},
{
"_index": "idtesttag",
"_type": "mydocs",
"_id": "1",
"_score": 0.8630463,
"_source": {
"id": 1,
"text": "some-text",
"tag": "A.B.c3"
}
}
]
}
}
仅需确保在进行增强测试时就能够进行彻底的测试,因为这完全会影响得分,并确保您使用DEV / TEST Elastic index中引入的产品数据来进行测试。
这样一来,如果您转向PROD Elastic,则在看到完全不同的结果时不会被惊吓。
很抱歉,我的回答很长,但是希望对您有所帮助!
答案 1 :(得分:0)
但是,(我认为)我希望标签以这种方式出现在倒排索引中(我可能不会考虑大小写,只是为了说明而将其包括在内):
然后,我要像这样搜索标签字段:
根据您在帖子中的描述。 “标签”字段,这是我的2美分。
您的Mysql数据应为1种类型(在6.5中,默认为'doc')。不过,您确实需要明确定义索引映射-尤其是在“标签”字段上,因为您似乎有搜索要求。
我将您的“标签”字段定义为以下内容的多字段:
(如果您不需要聚合,则只需使用自定义分析器定义一个“文本”类型字段)
仅供参考,Analyze API将向您展示ES在处理您的“标签”数据,并帮助您定义符合要求的映射。