Elasticsearch 对 Unicode 字符使用了错误的大小写折叠

Elasticsearch uses wrong Case Folding for Unicode Characters

在我的一个项目中,我尝试使用 Elasticsearch (1.7) 来查询数据。但是,它 returns unicode 字符的不同结果取决于它们是否大写。我尝试使用 icu_analyzer 来解决问题。

这里有一个小例子来说明我的问题。我的索引是这样的,

$ curl -X PUT http://localhost:9200/tr-test -d '
{
  "mappings": {
    "names": {
      "properties": {
        "name": {
          "type": "string"
        }
      }
    }
  },
  "settings": {
    "index": {
      "number_of_shards": "5",
      "number_of_replicas": "1",
      "analysis": {
        "filter": {
          "nfkc_normalizer": {
            "type": "icu_normalizer",
            "name": "nfkc"
          }
        },
        "analyzer": {
          "my_lowercaser": {
            "tokenizer": "icu_tokenizer",
            "filter": [
              "nfkc_normalizer"
            ]
          }
        }
      }
    }
  }
}'

这里有一个测试数据来证明我的问题。

$ curl -X POST http://10.22.20.140:9200/tr-test/_bulk -d '
{"index": {"_type":"names", "_index":"tr-test"}}
{"name":"BAHADIR"}'

这是一个类似的查询。如果我使用 BAHADIR 作为 query_string 查询,我可以很容易地找到我的测试数据。

$ curl -X POST http://10.22.20.140:9200/tr-test/_search -d '
{
  "query": {
    "filtered": {
      "query": {
        "query_string": {
          "query": "BAHADIR"
        }
      }
    }
  }
}'

在土耳其语中,BAHADIR 的小写版本是 bahadır。我在使用 bahadır 查询时期待相同的结果。但是 Elasticsearch 找不到我的数据。我无法通过使用 ICU 进行分析来解决这个问题。如果我用 bahadir.

查询,它工作得很好

我已经阅读 Living in a Unicode World and Unicode Case Folding。但无法解决我的问题。我仍然无法让 elasticsearch 使用正确的大小写折叠。

更新

我也尝试这样创建我的索引。

$ curl -X PUT http://localhost:9200/tr-test -d '
{
  "mappings": {
    "names": {
      "properties": {
        "name": {
          "type": "string",
          "analyzer" : "turkish"
        }
      }
    }
  },
  "settings": {
    "index": {
      "number_of_shards": "5",
      "number_of_replicas": "1"
    }
  }
}'

但我得到了相同的结果。如果我使用 BAHADIRbahadir 搜索可以找到我的数据,但无法通过搜索 bahadır 找到它,这是 BAHADIR 的正确小写版本。

您应该尝试在您的设置中使用 Turkish Language Analyzer

{
  "mappings": {
    "names": {
      "properties": {
        "name": {
          "type":     "string",
          "analyzer": "turkish" 
        }
      }
    }
  }
}

正如您在实现细节中看到的那样,它还定义了一个 turkish_lowercase,所以我想它会为您解决问题。如果您不需要土耳其语分析器的所有其他功能,请定义一个仅包含 turkish_lowercase

的自定义功能

如果您需要对您的name字段进行全文搜索,您还应该将查询方法更改为match query,这是对单个字段的基本全文搜索方法。

{
  "query": {
    "match": {
      "name": "bahadır"
    }
  }
}

另一方面,query string query 更复杂,并且可以在多个字段上进行搜索,从而允许使用高级语法;它还可以选择传递您要使用的 analyzer,因此如果您确实需要这种查询,您应该尝试在查询中传递 "analyzer": "turkish"。不过我不是查询字符串查询的专家。