【问题标题】:Elasicsearch mixing NGram with Simple query string queryElasticsearch 混合 NGram 与简单查询字符串查询
【发布时间】:2021-05-24 10:48:43
【问题描述】:

目前,我正在使用 Ngram 标记器对员工进行部分匹配。

我可以匹配全名电子邮件地址员工编号

我当前的设置如下:

"tokenizer": {
  "my_tokenizer": {
    "type": "ngram",
    "min_gram": 3,
    "max_gram": 3,
    "token_chars": [
      "letter",
      "digit"
    ]
  }
}

我面临的问题是 Employee Number 可以是 1 个字符长,并且由于 min_grammax_gram,我永远不能匹配。我也无法将 min_gram 设为 1,因为结果看起来不正确。

所以我尝试将 Ngram 与标准标记器混合,而不是在 Multimatch 搜索中进行,而是在做 simple_query_string。

这似乎也部分起作用。

我的问题是如何在所有 3 个字段上进行部分匹配,记住员工编号可以是 1 或 2 个字符长。如果我在单词或数字周围使用半引号,则完全匹配

在下面的示例中,如何搜索 11 并返回文档 4 和 5? 另外,如果我必须搜索部分匹配的 706,我希望返回文档 2,但如果我必须使用“7061”进行搜索,我只会返回文档 2

完整代码

PUT index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "english_exact": {
          "tokenizer": "standard",
          "filter": [
            "lowercase"
          ]
        },
        "my_analyzer": {
            "filter": [
              "lowercase",
              "asciifolding"
            ],
            "tokenizer": "my_tokenizer"
          }
      },
       "tokenizer": {
          "my_tokenizer": {
            "type": "ngram",
            "min_gram": 3,
            "max_gram": 3,
            "token_chars": [
              "letter",
              "digit"
            ]
          }
        },
       "normalizer": {
          "lowersort": {
            "type": "custom",
            "filter": [
              "lowercase"
            ]
          }
        }
    }
  },
  "mappings": {
    "properties": {
      "number": {
        "type": "text",
        "analyzer": "english",
        "fields": {
          "exact": {
            "type": "text",
            "analyzer": "english_exact"
          }
        }
      },
       "fullName": {
        "type": "text",
        "fields": {
          "ngram": {
            "type": "text",
            "analyzer": "my_analyzer"
          }
        },
        "analyzer": "standard"
      }
    }
  }
}
PUT index/_doc/1
{
  "number" : 1,
  "fullName": "Brenda eaton"
}

PUT index/_doc/2
{
  "number" : 7061,
  "fullName": "Bruce wayne"
}

PUT index/_doc/3
{
  "number" : 23,
  "fullName": "Bruce Banner"
}

PUT index/_doc/4
{
  "number" : 111,
  "fullName": "Cat woman"
}

PUT index/_doc/5
{
  "number" : 1112,
  "fullName": "0723568521"
}

GET index/_search
{
  "query": {
    "simple_query_string": {
      "fields": [ "fullName.ngram", "number.exact"],
      "query": "11"
    }
  }
}

【问题讨论】:

    标签: elasticsearch n-gram


    【解决方案1】:

    您需要更改number.exact字段的分析器并减少min_gram 计数为2。修改索引映射如下图

    添加一个工作示例

    索引映射:

        {
      "settings": {
        "analysis": {
          "analyzer": {
            "english_exact": {
              "tokenizer": "standard",
              "filter": [
                "lowercase"
              ]
            },
            "my_analyzer": {
              "filter": [
                "lowercase",
                "asciifolding"
              ],
              "tokenizer": "my_tokenizer"
            }
          },
          "tokenizer": {
            "my_tokenizer": {
              "type": "ngram",
              "min_gram": 2,
              "max_gram": 3,
              "token_chars": [
                "letter",
                "digit"
              ]
            }
          },
          "normalizer": {
            "lowersort": {
              "type": "custom",
              "filter": [
                "lowercase"
              ]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "number": {
            "type": "keyword",          // note this
            "fields": {
              "exact": {
                "type": "text",
                "analyzer": "my_analyzer"
              }
            }
          },
          "fullName": {
            "type": "text",
            "fields": {
              "ngram": {
                "type": "text",
                "analyzer": "my_analyzer"
              }
            },
            "analyzer": "standard"
          }
        }
      }
    }
    

    搜索查询:

    {
      "query": {
        "simple_query_string": {
          "fields": [ "fullName.ngram", "number.exact"],
          "query": "11"
        }
      }
    }
    

    搜索结果:

    "hits": [
          {
            "_index": "66311552",
            "_type": "_doc",
            "_id": "4",
            "_score": 0.9929736,
            "_source": {
              "number": 111,
              "fullName": "Cat woman"
            }
          },
          {
            "_index": "66311552",
            "_type": "_doc",
            "_id": "5",
            "_score": 0.8505551,
            "_source": {
              "number": 1112,
              "fullName": "0723568521"
            }
          }
        ]
    

    更新 1:

    如果只需要搜索1,将number字段的数据类型从text类型修改为keyword类型,如上面的索引映射所示。

    搜索查询:

    {
      "query": {
        "simple_query_string": {
          "fields": [ "fullName.ngram", "number.exact","number"],
          "query": "1"
        }
      }
    }
    

    搜索结果将是

    "hits": [
          {
            "_index": "66311552",
            "_type": "_doc",
            "_id": "1",
            "_score": 1.3862942,
            "_source": {
              "number": 1,
              "fullName": "Brenda eaton"
            }
          }
        ]
    

    更新 2:

    您可以为 fullName 字段和 number 字段使用两个带有 n-gram 标记器的单独分析器。使用以下索引映射进行修改:

    {
      "settings": {
        "analysis": {
          "analyzer": {
            "english_exact": {
              "tokenizer": "standard",
              "filter": [
                "lowercase"
              ]
            },
            "name_analyzer": {
              "filter": [
                "lowercase",
                "asciifolding"
              ],
              "tokenizer": "name_tokenizer"
            },
            "number_analyzer": {
              "filter": [
                "lowercase",
                "asciifolding"
              ],
              "tokenizer": "number_tokenizer"
            }
          },
          "tokenizer": {
            "name_tokenizer": {
              "type": "ngram",
              "min_gram": 3,
              "max_gram": 3,
              "token_chars": [
                "letter",
                "digit"
              ]
            },
             "number_tokenizer": {
              "type": "ngram",
              "min_gram": 2,
              "max_gram": 3,
              "token_chars": [
                "letter",
                "digit"
              ]
            }
          },
          "normalizer": {
            "lowersort": {
              "type": "custom",
              "filter": [
                "lowercase"
              ]
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "number": {
            "type": "keyword",
            "fields": {
              "exact": {
                "type": "text",
                "analyzer": "number_analyzer"
              }
            }
          },
          "fullName": {
            "type": "text",
            "fields": {
              "ngram": {
                "type": "text",
                "analyzer": "name_analyzer"
              }
            },
            "analyzer": "standard"
          }
        }
      }
    }
    

    【讨论】:

    • 太棒了,让我检查一下
    • 只是出于好奇,如果我只需要搜索 1 而不是 11,这将不起作用吗?我假设我必须将 ngram 更新为 min_gram: 1,这可能会在搜索全名时丢失搜索结果
    • @R4nc1d 请仔细阅读我更新的部分答案,如果这能解决您的问题,请告诉我?
    • +1 为您的帮助,以上绝对解决了 95% 的问题。我只看到一个问题,如果我使用您的设置进行更新,然后搜索“eaton”,我会返回“Cat Woman”,我怀疑这是因为“min_gram”:2,有没有办法将其保持在 3?除了这个问题,我认为它的工作非常准确
    • @R4nc1d 我已经更新了索引映射,请检查一下映射是否能解决您的问题?
    猜你喜欢
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多