1

我有像 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. 请问这个映射如何才能实现上面提到的 自动完成功能

4

1 回答 1

0

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

  1. 创建一个自定义分析器,根据我们的要求对数据进行标记。
  2. 使用结合前缀(用于自动完成)和匹配的布尔查询进行数字搜索。

下面是使用 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,应该在样本数据中带来 2 个文档,I420hcc420必须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"
        }
      }
    ]
于 2020-04-01T16:25:18.113 回答