重生之我们在ES顶端相遇第5章-常用字段类型

思维导图

重生之我们在ES顶端相遇第5章-常用字段类型_第1张图片

前置

在第4章,我们提到了 keyword(一笔带过)。在本章,我们将介绍 ES 的字段类型。全面的带大家了解 ES 各个字段类型的使用场景。

字段类型

ES 支持以下字段类型(仅介绍开发中常用,更多内容请自行阅读 官方文档)。

Keyword
基本介绍

手动设置字段类型为 keyword

PUT /test3
{
  "mappings": {
    "properties": {
      "tags": {
        "type": "keyword"
      }
    }
  }
}

写入数据

PUT /test3/_doc/1
{
  "tags": "hello world"
}

keyword 其实就是字符串,输入什么,存储就是什么。

适用场景

keyword 适用于 排序、聚合、term(精确查询) 查询场景中。
例如

GET /test3/_search
{
  "query": {
    "term": {
      "tags": {
        "value": "hello"
      }
    }
  }
}
查询优化

有 2 个对查询优化重要的点:

  1. 数字类型(int, long)如果不需要使用范围查询,则建议设置为 keyword
  2. term 查询在 keyword 上的搜索速度总是快于数字类型。
Text
基本介绍

与 keyword 相对的则是 text。在第三章,我们介绍了全文搜索 match 的用法。你可能会好奇,为啥默认写入的数据就可以使用全文搜索。因为当输入是无规则字符串时,字段类型就是 text。(别着急,默认的字段类型,一会我们就会详细介绍)

手动设置字段类型为 text

# 先删除索引
DELETE test3

PUT /test3
{
  "mappings": {
    "properties": {
      "tags": {
        "type": "text"
      }
    }
  }
}
适用场景

text 适用场景:全文搜索
text 字段会对输入进行分词。
例如

PUT /test3/_doc/1
{
  "tags": "hello world"
}

tags 会被分词存储为 hello、world 2个词。
当然,具体被分词为什么,其实跟我们设置的分词器有关(后续讲解,这里先有个概念)。

不适用场景

text 不适用场景:排序、聚合、脚本。
如果你在 text 字段上,进行排序、聚合,或者脚本操作,都会收到以下异常。
Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [name] in order to load field data by uninverting the inverted index. Note that this can use significant memory.

例如:

GET /test3/_search
{
  "sort": [
    {
      "tags": {
        "order": "desc"
      }
    }
  ]
}

# 聚合
GET /test3/_search
{
  "size": 0,
  "aggs": {
    "popular_tags": {
      "terms": {
        "field": "tags"
      }
    }
  }
}

# 脚本操作
GET /test3/_search
{
  "query": {
    "script": {
      "script": "doc['tags'].value == 'hello'"
    }
  }
}
illegal_argument_exception 异常解决方式

要解决该异常,有2种方法

  1. 使用多字段类型,即在该字段上面再建一个 keyword 类型(强烈建议)
DELETE test3

PUT test3
{
  "mappings": {
    "properties": {
      "tags": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

排序、聚合时,则使用 tags.keyword。需要全文索引时,依然可以使用 tags 字段。

GET /test3/_search
{
  "sort": [
    {
      "tags.keyword": {
        "order": "desc"
      }
    }
  ]
}
  1. text 字段上启用 fielddata(不建议!不建议!不建议!)
DELETE test3

PUT /test3/_mapping
{
  "properties": {
    "tags": {
      "type": "text",
       "fielddata": true
    }
  }
}

PS:在 text 字段上启用 fielddata,会消耗非常大的内存!!!

Date

手动指定字段类型为 date

PUT /test3
{
  "mappings": {
    "properties": {
      "ctime": {
        "type": "date"
      }
    }
  }
}

未指定 format 参数时,默认的值为 strict_date_optional_time||epoch_millis
该默认值接收以下数据

# 秒时间戳
PUT /test3/_doc/1
{
  "ctime": 1721135125
}
# 毫秒时间戳
PUT /test3/_doc/2
{
  "ctime": 1721135125000
}
# datetime
PUT /test3/_doc/3
{
  "ctime":"2024-07-16T12:10:30Z"
}
# date
PUT /test3/_doc/4
{
  "ctime": "2024-07-15"
}

# 对数据排序
GET test3/_search
{
  "sort": { "ctime": "asc"} 
}
format 参数

我们可以手动指定允许的数据格式。例如

PUT /test3
{
  "mappings": {
    "properties": {
      "ctime": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis||epoch_second"
      }
    }
  }
}
存储时间仅为秒时间戳

如果时间为秒时间戳,可以考虑使用 epoch_second

PUT my-index-000001
{
  "mappings": {
    "properties": {
      "ctime": {
        "type":   "date",
        "format": "strict_date_optional_time||epoch_second"
      }
    }
  }
}

PUT /test3/_doc/1
{
  "ctime": 1721135125
}

# 以下查询,时间会被格式化
GET test3/_search
{
  "fields": [ {"field": "ctime"}]
}
数字类型

在复习一下,如果不需要范围查询,建议使用 keyword 存储(后续在进阶篇会讲原理)。

scaled_float

ES 除了支持常见的数字类型。如:long、integer、short、byte、double、float
还针对浮点数,有一个优化的类型 scaled_float
如果我们能够得知我们的浮点数最多有多少个小数点。使用该类型,在空间存储上会比浮点数更好。

PUT /test3
{
  "mappings": {
    "properties": {
      "sf": {
        "type": "scaled_float",
        "scaling_factor": 100
      }
    }
  }
}

上面的意思为:存储时,* 100。即,将浮点数变为整数。

Boolean
PUT /test3
{
  "mappings": {
    "properties": {
      "enable": {
        "type": "boolean"
      }
    }
  }
}
  • false, “false”, “” (empty string) 均被认为是 false
  • true, “true” 均被认为是 true
POST /test3/_doc
{
  "enable": false
}
POST /test3/_doc
{
  "enable": "false"
}
POST /test3/_doc
{
  "enable": ""
}
POST /test3/_doc
{
  "enable": true
}
POST /test3/_doc
{
  "enable": "true"
}

GET /test3/_search
{
  "query": {
    "term": {
      "enable": {
        "value": false
      }
    }
  }
}
Object

写入一个 manager 对象

PUT test3/_doc/1
{ 
  "region": "US",
  "manager": { 
    "age":     30,
    "name": { 
      "first": "John",
      "last":  "Smith"
    }
  }
}

在 ES 内部,该文档被索引为一个简单的键值对列表,大致如下

{
  "region":             "US",
  "manager.age":        30,
  "manager.name.first": "John",
  "manager.name.last":  "Smith"
}

例如,我们可以查询 manager.age=30 的文档

GET /test3/_search
{
  "query": {
    "term": {
      "manager.age": {
        "value": 30
      }
    }
  }
}

上述文档的显式映射如下

PUT /test3
{
  "mappings": {
    "properties": { 
      "region": {
        "type": "keyword"
      },
      "manager": { 
        "properties": {
          "age":  { "type": "integer" },
          "name": { 
            "properties": {
              "first": { "type": "text" },
              "last":  { "type": "text" }
            }
          }
        }
      }
    }
  }
}
Array
  1. 不支持混合数据类型的数组
POST /test3/_doc
{
  "arr": ["12", 12, false]
}
  1. 无法查询数组中的每个对象
PUT test3/_doc/1
{
  "group" : "fans",
  "user" : [ 
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

# 查询 user.first=Alice & user.last=White。你可能会使用以下写法,但实际上并不能正确工作

GET test3/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "user.first": "Alice" }},
        { "match": { "user.last":  "Smith" }}
      ]
    }
  }
}

如果你的索引结构是这么设计的,并且有这样的需求,可能需要考虑下如何做优化了。例如,将表铺平。

PS:虽然 nested 嵌套类型可以解决该问题,但开发中会尽可能的把数据结构铺平,从而避免使用 nested 嵌套类型。这里不对 nested 过多介绍,因为开发中真的很不推荐使用。

  1. 开发中仅推荐基本数据类型数组,不推荐对象数组,如果你有第2 点描述的查询需求
PUT test3
{
  "mappings": {
    "properties": {
      "arr": {
        "type": "keyword"
      }
    }
  }
}

PUT test3/_doc/1
{
  "arr": ["1", "2", "3"]
}

GET test3/_search
{
  "query": {
    "term": {
      "arr": {
        "value": "1"
      }
    }
  }
}

你可能感兴趣的:(Elasticsearch,elasticsearch)