【问题标题】:Elasticsearch with ngram indexing not finding partial matches具有 ngram 索引的 Elasticsearch 未找到部分匹配项
【发布时间】:2015-07-02 00:21:09
【问题描述】:

所以我有一个这样创建的弹性搜索索引:

curl -XPUT 'http://localhost:9200/person' -d '{
    "settings": {
        "number_of_shards": 1,
        "analysis": {
            "filter": {
                "autocomplete_filter": {
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter"
                    ]
                }
            }
        }
    }
}'

在查询名为“ian”的人时,我得到两个结果

curl -XGET http://localhost:9200/person/_search -d '{
        "query": {
                "match": {
                        "_all": "ian"
                }
        }
}’

但是在仅查询字母 ia 时,我应该得到尽可能多或更多的结果,但我没有得到任何结果:

curl -XGET http://localhost:9200/person/_search -d '{
        "query": {
                "match": {
                        "_all": "ia"
                }
        }
}’ 

我的edge_ngram 过滤器设置有问题吗?我该如何解决这个问题?

编辑:澄清一下,我希望我的插入语句看起来像这样

curl -XPOST "http://localhost:9200/person/RANDOM_STRING HERE/ANOTHER_RANDOM_STRING" -d "{
 "field1" : "value",
 "field2" : "value",
 "field3" : "value"
}"

插入后,我希望对所有字段进行 edge_ngram 分析,以便我可以按任何这些字段的部分字符串搜索并返回此结果。

【问题讨论】:

    标签: elasticsearch lucene n-gram


    【解决方案1】:

    如果您只想对每种类型和所有属性使用分析器(除非另有说明),您只需为索引设置“默认”分析器。我在 ES 文档中找不到这个(它们并不总是非常用户友好),但这里有一个例子。我使用的是 ES 1.5,但我认为这并不重要。

    PUT /person
    {
       "settings": {
          "number_of_shards": 1,
          "analysis": {
             "filter": {
                "autocomplete_filter": {
                   "type": "edge_ngram",
                   "min_gram": 1,
                   "max_gram": 20
                }
             },
             "analyzer": {
                "default": {
                   "type": "custom",
                   "tokenizer": "standard",
                   "filter": [
                      "lowercase",
                      "autocomplete_filter"
                   ]
                }
             }
          }
       }
    }
    

    然后我索引了文档并运行了您的查询,它运行良好:

    POST /person/doc/_bulk
    {"index":{"_id":1}}
    {"name":"Ian"}
    {"index":{"_id":2}}
    {"name":"Bob Smith"}
    
    POST /person/_search
    {
       "query": {
          "match": {
             "_all": "ia"
          }
       }
    }
    ...
    {
       "took": 1,
       "timed_out": false,
       "_shards": {
          "total": 1,
          "successful": 1,
          "failed": 0
       },
       "hits": {
          "total": 1,
          "max_score": 1.4142135,
          "hits": [
             {
                "_index": "person",
                "_type": "doc",
                "_id": "1",
                "_score": 1.4142135,
                "_source": {
                   "name": "Ian"
                }
             }
          ]
       }
    }
    

    代码如下:

    http://sense.qbox.io/gist/4e2114aafc4f3c507b4f23da8bb83f3ab00e2288

    【讨论】:

    • 非常感谢!你是最棒的
    【解决方案2】:

    _all 字段将使用默认分析器“标准”,除非您为其指定一个。所以 _all 字段中的标记不是 edge_ngram。因此搜索“ia”没有结果。您通常希望避免使用 _all 字段进行部分匹配搜索,因为它可能会产生意外或令人困惑的结果。

    如果您仍然需要使用 _all 字段,那么还要专门将分析器指定为“自动完成”。

    【讨论】:

    • 您能举个例子吗?我想为所有属性设置默认映射以索引所有内容
    【解决方案3】:

    您没有指定任何使用您的分析器的类型。所以你定义了分析器,但没有使用它。当您将文档保存为新类型时,映射将被隐式定义,并且将使用 standard analyzer,它不会创建部分单词,因此您对“ia”的搜索不会匹配任何内容。

    处理此问题的一种方法是显式定义类型,并指定要在映射中使用的分析器。这是一个示例,其中索引名称为“person”(如您的),类型名称为“doc”,属性“name”使用您的分析器进行索引(但不用于搜索):

    PUT /person
    {
        "settings": {
            "number_of_shards": 1,
            "analysis": {
                "filter": {
                    "autocomplete_filter": {
                        "type":     "edge_ngram",
                        "min_gram": 1,
                        "max_gram": 20
                    }
                },
                "analyzer": {
                    "autocomplete": {
                        "type":      "custom",
                        "tokenizer": "standard",
                        "filter": [
                            "lowercase",
                            "autocomplete_filter"
                        ]
                    }
                }
            }
        },
        "mappings": {
            "doc":{
                "properties": {
                    "name": {
                        "type": "string",
                        "index_analyzer": "autocomplete",
                        "search_analyzer": "standard"
                    }
                }
            }
        }
    }
    

    为了测试它,我添加了几个文档:

    POST /person/doc/_bulk
    {"index":{"_id":1}}
    {"name":"Ian"}
    {"index":{"_id":2}}
    {"name":"Bob Smith"}
    

    然后针对"name" 字段运行匹配查询:

    POST /person/_search
    {
       "query": {
          "match": {
             "name": "ia"
          }
       }
    }
    ...
    {
       "took": 2,
       "timed_out": false,
       "_shards": {
          "total": 1,
          "successful": 1,
          "failed": 0
       },
       "hits": {
          "total": 1,
          "max_score": 1,
          "hits": [
             {
                "_index": "person",
                "_type": "doc",
                "_id": "1",
                "_score": 1,
                "_source": {
                   "name": "Ian"
                }
             }
          ]
       }
    }
    

    这是我用来测试一些不同事物的一些代码,包括使用"_all" 字段以使您的原始查询正常工作:

    http://sense.qbox.io/gist/61df5d17343651884c9422198b6a6bc00a6acb04

    【讨论】:

    • 嗯,这个问题是它只在类型为doc 时有效,即使这样它也只适用于name 属性。我希望这可以索引每种类型的每个属性。
    • 查看我的编辑,我将给出一个更具体的示例来说明我希望插入的外观
    • 哦,哈哈,那就简单了。只需将分析仪的名称更改为“默认”即可。我将发布另一个答案。
    • 总是那么小!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2013-09-11
    • 2020-08-16
    • 2016-08-12
    • 2018-11-23
    • 1970-01-01
    • 2016-01-12
    相关资源
    最近更新 更多