字母数字的 ElasticSearch 分析器自动完成功能

ElasticSearch analyzer auto-complete feature for alphanumeric

我有 Hcc18、HCC23、I23 等字母数字代码,我想将其存储在 ElasticSearch 中。在此基础上,我想构建以下两个功能:-

  1. 用户可以搜索完整的字母数字代码或仅搜索整数部分。
    示例: 对于 hcc15 或 15,hcc15 应该在输出中并位于结果的顶部。
  2. 自动完成功能:当用户键入 I42 时,结果应包含 I420、I421 等。

我的 Elasticsearch 当前映射是:

"mappings": {
  "properties": {
    "code": {
      "type": "text",
      "analyzer": "autoanalyer"
    }
  }
},
"settings": {
  "analysis": {
    "analyzer": {
      "autoanalyer": {
        "tokenizer": "standard",
        "filter": [
          "lowercase",
        ]
      }
    },
    "tokenizer": {
      "autotoken": {
        "type": "simple_pattern",
        "pattern": "[0-9]+"
      }
    }
  }
}

正在查询:

{
    "min_score": 0.1,
    "from": 0,
    "size": 10000,
    "query": {
        "bool": {
            "should": [{ "match": {"code": search_term}}]
        }
    }
}

两个问题,我用这个方法面临的是:-

  1. 假设我搜索 I420,现在因为映射仅基于数字, 我得到了与数字 420 相关的所有代码,但确切的 匹配 I420 没有排在首位。

  2. 请问这个映射怎么才能实现上面说的 自动完成功能.

您有多个要求,所有这些都可以使用

实现
  1. 创建一个 custom analyzer 根据我们的要求标记数据。
  2. 使用 bool 查询结合 the prefix(用于自动完成)和数字搜索匹配。

下面是使用 OP 数据和查询的分步示例。

索引定义

{
    "settings": {
        "analysis": {
            "analyzer": {
                "my_analyzer": {
                    "tokenizer": "autotoken" -->used your analyzer to extract numbers
                }
            },
            "tokenizer": {
                "autotoken": {
                    "type": "simple_pattern",
                    "pattern": "[0-9]+",
                    "preserve_original": true
                }
            }
        }
    },
    "mappings": {
        "properties": {
            "code": {
                "type": "keyword",
                "fields": {
                    "number": {
                        "type": "text",
                        "analyzer" : "my_analyzer"
                    }
                }
            }
        }
    }
}

索引几个文档

{
  "code" : "hcc420"
}

{
  "code" : "HCC23"
}

{
  "code" : "I23"
}

{
  "code" : "I420"
}

{
  "code" : "I421"
}

{
  "code" : "hcc420"
}

搜索查询(问题 1,搜索 I420,应该在样本数据 I420hcc420 中带 2 个文档,但 I420 必须有更多的分数作为完全匹配)

{
    "query": {
        "bool": {
            "should": [
                {
                    "prefix": {
                        "code": {
                            "value": "I420"
                        }
                    }
                },
                {
                    "match": {
                        "code.number": "I420"
                    }
                }
            ]
        }
    }
}

结果

"hits": [
      {
        "_index": "so_number",
        "_type": "_doc",
        "_id": "4",
        "_score": 2.0296195, --> note exact match having high score
        "_source": {
          "code": "I420"
        }
      },
      {
        "_index": "so_number",
        "_type": "_doc",
        "_id": "7",
        "_score": 1.0296195,
        "_source": {
          "code": "hcc420"
        }
      }
    ]

第 2 部分:相同的搜索查询可以使用自动完成功能

所以搜索 I42 必须从示例文档 I420I421

{
    "query": {
        "bool": {
            "should": [
                {
                    "prefix": {
                        "code": {
                            "value": "I42"
                        }
                    }
                },
                {
                    "match": {
                        "code.number": "I42"
                    }
                }
            ]
        }
    }
}

结果

 "hits": [
      {
        "_index": "so_number",
        "_type": "_doc",
        "_id": "4",
        "_score": 1.0,
        "_source": {
          "code": "I420"
        }
      },
      {
        "_index": "so_number",
        "_type": "_doc",
        "_id": "5",
        "_score": 1.0,
        "_source": {
          "code": "I421"
        }
      }
    ]

再举个例子,查号,查420一定要带hcc420I420

搜索查询

 {
        "query": {
            "bool": {
                "should": [
                    {
                        "prefix": {
                            "code": {
                                "value": "420"
                            }
                        }
                    },
                    {
                        "match": {
                            "code.number": "420"
                        }
                    }
                ]
            }
        }
    }

And whoa, again it gave expected results 

Result
------


 "hits": [
      {
        "_index": "so_number",
        "_type": "_doc",
        "_id": "4",
        "_score": 1.0296195,
        "_source": {
          "code": "I420"
        }
      },
      {
        "_index": "so_number",
        "_type": "_doc",
        "_id": "7",
        "_score": 1.0296195,
        "_source": {
          "code": "hcc420"
        }
      }
    ]