这可能是一个非常常见的问题,但是到目前为止我得到的答案并不令人满意。
问题:我有一个由近100个字段组成的es索引。大多数字段都是string
type 并设置为analyzed
. 但是,查询既可以是部分的(match
),也可以是精确的(更像term
)。因此,如果我的索引包含一个带有 value 的字符串字段super duper cool pizza
,则可能存在部分查询,duper super
并且将与文档匹配,但是,可能存在cool pizza
不应该与文档匹配的精确查询。另一方面,Super Duper COOL PIzza
又要与这个文件相匹配。
到目前为止,部分匹配部分很容易,我在查询中使用AND
了运算符。match
但是无法完成其他类型。
我查看了与此问题相关的其他帖子,并且该帖子包含最接近的解决方案: Elasticsearch 精确匹配分析字段
在这三个解决方案中,第一个感觉非常复杂,因为我有很多字段并且我不使用 REST api,我使用 QueryBuilders 和 NativeSearchQueryBuilder 从他们的 Java api 动态创建查询。它还会产生许多可能的模式,我认为这些模式会导致性能问题。
第二个是一个更简单的解决方案,但同样,我必须维护更多(几乎)冗余数据,而且我认为使用term
查询永远不会解决我的问题。
最后一个我认为有问题,它不会阻止super duper
匹配super duper cool pizza
不是我想要的输出。
那么我还有其他方法可以实现目标吗?如果需要进一步清除问题,我可以发布一些示例映射。我也已经保留了源代码(以防万一)。请随时提出任何改进建议。
提前致谢。
[更新]
最后,我使用multi_field
,为精确查询保留一个原始字段。当我插入时,我对数据使用了一些自定义修改,在搜索过程中,我对输入文本使用了相同的修改例程。这部分不由 Elasticsearch 处理。如果你想这样做,你还必须设计合适的分析器。
索引设置和映射查询:
PUT test_index
POST test_index/_close
PUT test_index/_settings
{
"index": {
"analysis": {
"analyzer": {
"standard_uppercase": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "keyword",
"filter": ["uppercase"]
}
}
}
}
}
PUT test_index/doc/_mapping
{
"doc": {
"properties": {
"text_field": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"analyzer": "standard_uppercase"
}
}
}
}
}
}
POST test_index/_open
插入一些示例数据:
POST test_index/doc/_bulk
{"index":{"_id":1}}
{"text_field":"super duper cool pizza"}
{"index":{"_id":2}}
{"text_field":"some other text"}
{"index":{"_id":3}}
{"text_field":"pizza"}
准确查询:
GET test_index/doc/_search
{
"query": {
"bool": {
"must": {
"bool": {
"should": {
"term": {
"text_field.raw": "PIZZA"
}
}
}
}
}
}
}
回复:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.4054651,
"hits": [
{
"_index": "test_index",
"_type": "doc",
"_id": "3",
"_score": 1.4054651,
"_source": {
"text_field": "pizza"
}
}
]
}
}
部分查询:
GET test_index/doc/_search
{
"query": {
"bool": {
"must": {
"bool": {
"should": {
"match": {
"text_field": {
"query": "pizza",
"operator": "AND",
"type": "boolean"
}
}
}
}
}
}
}
}
回复:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "test_index",
"_type": "doc",
"_id": "3",
"_score": 1,
"_source": {
"text_field": "pizza"
}
},
{
"_index": "test_index",
"_type": "doc",
"_id": "1",
"_score": 0.5,
"_source": {
"text_field": "super duper cool pizza"
}
}
]
}
}
PS:这些是生成的查询,这就是为什么会有一些冗余块,因为会有许多其他字段连接到查询中。
可悲的是,现在我需要再次重写整个映射:(