我有一些带有名字字段的文件。我使用名称字段的分析版本进行搜索,使用not_analyzed
进行排序。排序发生在一个级别,即名称首先按字母顺序排序。但是在字母表列表中,名称按字典顺序排序,而不是按字母顺序排序。
这是我使用的映射:
{
"mappings": {
"seing": {
"properties": {
"name": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
}
任何人都可以为此提供解决方案吗?
答案 0 :(得分:13)
深入研究Elasticsearch文档,我偶然发现了这个:
不区分大小写的排序
想象一下,我们有三个名称字段包含的用户文档 分别是Boffey,BROWN和bailey。首先我们将申请 在字符串排序和使用a的多字段中描述的技术 not_analyzed字段用于排序:
PUT /my_index
{
"mappings": {
"user": {
"properties": {
"name": { //1
"type": "string",
"fields": {
"raw": { //2
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
}
}
analyzed
name
字段用于搜索。not_analyzed
name.raw
字段用于排序。上述搜索请求将按此顺序返回文档: 布朗,波菲,贝利。这被称为词典顺序 反对按字母顺序排列。基本上,用于的字节 表示大写字母的值低于用于的字节 表示小写字母,因此名称用 首先是最低字节。
这可能对计算机有意义,但没有多大意义 人们会合理地期望对这些名称进行排序 按字母顺序排列,无论如何。要实现这一点,我们需要索引 每个名称的字节排序方式与排序相对应 我们想要的订单。
换句话说,我们需要一个发射单个小写的分析器 令牌:
遵循这个逻辑,您需要使用自定义关键字分析器小写它来代替存储原始文档:
PUT /my_index
{
"settings" : {
"analysis" : {
"analyzer" : {
"case_insensitive_sort" : {
"tokenizer" : "keyword",
"filter" : ["lowercase"]
}
}
}
},
"mappings" : {
"seing" : {
"properties" : {
"name" : {
"type" : "string",
"fields" : {
"raw" : {
"type" : "string",
"analyzer" : "case_insensitive_sort"
}
}
}
}
}
}
}
现在按name.raw
排序应按按字母顺序顺序排序,而不是词典。
使用Marvel在本地计算机上进行快速测试:
索引结构:
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"case_insensitive_sort": {
"tokenizer": "keyword",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"user": {
"properties": {
"name": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
},
"keyword": {
"type": "string",
"analyzer": "case_insensitive_sort"
}
}
}
}
}
}
}
测试数据:
PUT /my_index/user/1
{
"name": "Tim"
}
PUT /my_index/user/2
{
"name": "TOM"
}
使用原始字段查询:
POST /my_index/user/_search
{
"sort": "name.raw"
}
结果:
{
"_index" : "my_index",
"_type" : "user",
"_id" : "2",
"_score" : null,
"_source" : {
"name" : "TOM"
},
"sort" : [
"TOM"
]
},
{
"_index" : "my_index",
"_type" : "user",
"_id" : "1",
"_score" : null,
"_source" : {
"name" : "Tim"
},
"sort" : [
"Tim"
]
}
使用小写字符串查询:
POST /my_index/user/_search
{
"sort": "name.keyword"
}
结果:
{
"_index" : "my_index",
"_type" : "user",
"_id" : "1",
"_score" : null,
"_source" : {
"name" : "Tim"
},
"sort" : [
"tim"
]
},
{
"_index" : "my_index",
"_type" : "user",
"_id" : "2",
"_score" : null,
"_source" : {
"name" : "TOM"
},
"sort" : [
"tom"
]
}
我怀疑你的第二个结果是正确的。
答案 1 :(得分:1)
normalizer
字段的keyword
属性类似于
analyzer
,但可以保证分析链
产生一个令牌。
在对关键字建立索引之前以及在normalizer
处应用
通过查询解析器搜索keyword
字段时的搜索时间
match
查询。
PUT index
{
"settings": {
"analysis": {
"normalizer": {
"my_normalizer": {
"type": "custom",
"char_filter": [],
"filter": ["lowercase", "asciifolding"]
}
}
}
},
"mappings": {
"type": {
"properties": {
"foo": {
"type": "keyword",
"normalizer": "my_normalizer"
}
}
}
}
}
PUT index/type/1
{
"foo": "BÀR"
}
PUT index/type/2
{
"foo": "bar"
}
PUT index/type/3
{
"foo": "baz"
}
POST index/_refresh
GET index/_search
{
"query": {
"match": {
"foo": "BAR"
}
}
}
由于BÀR
在以下位置转换为bar
,因此上述查询匹配文档1和2:
索引和查询时间。
{
"took": $body.took,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.2876821,
"hits": [
{
"_index": "index",
"_type": "type",
"_id": "2",
"_score": 0.2876821,
"_source": {
"foo": "bar"
}
},
{
"_index": "index",
"_type": "type",
"_id": "1",
"_score": 0.2876821,
"_source": {
"foo": "BÀR"
}
}
]
}
}
此外,在索引之前先转换关键字这一事实也意味着 聚合返回归一化值:
GET index/_search
{
"size": 0,
"aggs": {
"foo_terms": {
"terms": {
"field": "foo"
}
}
}
}
返回
{
"took": 43,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0.0,
"hits": []
},
"aggregations": {
"foo_terms": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "bar",
"doc_count": 2
},
{
"key": "baz",
"doc_count": 1
}
]
}
}
}
来源:Normaliser
答案 2 :(得分:0)
只是一些基于@PiwEL 回答的附加组件。
如果您使用的是 nodejs version 的弹性搜索,如果您的索引已经存在,则您不能真正更新设置:
await esClient.indices.putSettings({
index,
body: {
analysis: {
normalizer: {
my_normalizer: {
type: "custom",
char_filter: [],
filter: ["lowercase", "asciifolding"],
},
},
},
},
});
这个 API 总是抛出异常。所以我最终在创建索引时创建了这个设置,因此必须删除并重新创建索引。更多细节可追溯here
所以当使用 NodeJs 客户端时,以下对我有用。
await esClient.indices.create({
index,
body: {
settings: {
analysis: {
normalizer: {
my_normalizer: {
type: "custom",
char_filter: [],
filter: ["lowercase", "asciifolding"],
},
},
},
},
mappings: {
properties: {
id: {
type: "keyword",
},
name: {
type: "text",
fields: {
keyword: {
type: "keyword",
normalizer: "my_normalizer",
},
},
},
seedless: {
type: "boolean",
},
origin: { type: "text" },
},
},
},
});