一、概述
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。
elasticsearch(集群)中可以包含多个索引(数据库**)** ,每个索引中可以包含多个类型(表) ,每个类型下又包含多个文档(行) ,每个文档中又包含多个字段(列)。
ElasticSearch是面向文档,关系型数据库和ElasticSearch客观对比!一切都是JSON!
ElasticSearch是面向文档型的数据库,一条数据在这里就是一个文档。比如:
{
"name" : "John",
"sex" : "Male",
"age" : 25,
"birthDate": "1990/05/01",
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
1.1 与数据库对比
- 索引:数据库
- 类型:数据表
- 文档:表里的数据
- 属性:表列名
ElasticSearch6.0之后移除了类型的概念。7.x使用类型会警告,8.x将彻底废除。
Relational DB | ElasticSearch |
---|---|
数据库(database) | 索引(indices) |
表(tables) | types <慢慢会被弃用!> |
行(rows) | documents |
字段(columns) | fields |
1.2映射(mapping)
mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其它就是处理es里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。相当于mysql中的创建表的过程,设置主键外键等等
1.2.1动态映射—Dynamic Mapping
Dynamic Mapping 机制使我们不需要手动定义 Mapping,ES 会自动根据文档信息来判断字段合适的类型,但是有时候也会推算的不对,比如地理位置信息有可能会判断为 Text,当类型如果设置不对时,会导致一些功能无法正常工作,比如 Range 查询。
ES 类型的自动识别是基于 JSON 的格式,如果输入的是 JSON 是字符串且格式为日期格式,ES 会自动设置成 Date 类型;当输入的字符串是数字的时候,ES 默认会当成字符串来处理,可以通过设置来转换成合适的类型;如果输入的是 Text 字段的时候,ES 会自动增加 keyword 子字段,还有一些自动识别如下图所示:
下面我们通过一个例子是看看是怎么类型自动识别的,输入如下请求,创建索引:
然后使用 GET /mapping_test/_mapping 查看,结果如下图所示:
可以从结果中看出,ES 会根据文档信息自动推算出合适的类型。
万一我想修改 Mapping 的字段类型,能否更改呢?让我们分以下两种情况来探究下:
修改 Mapping 字段类型?
如果是新增加的字段,根据 Dynamic 的设置分为以下三种状况:
1、当 Dynamic 设置为 false 时,索引的 Mapping 是不会被更新的,新增字段的数据无法被索引,也就是无法被搜索,但是信息会出现在 _source 中。
2、当 Dynamic 设置为 strict 时,文档写入会失败。
3、当 Dynamic 设置为 true 时,一旦有新增字段的文档写入,Mapping 也同时被更新。
另外一种是字段已经存在,这种情况下,ES 是不允许修改字段的类型的,因为 ES 是根据 Lucene 实现的倒排索引,一旦生成后就不允许修改,如果希望改变字段类型,必须使用 Reindex API 重建索引。
不能修改的原因是如果修改了字段的数据类型,会导致已被索引的无法被搜索,但是如果是增加新的字段,就不会有这样的影响。
1.2.2静态映射
静态映射的意思就是在定义索引时,就把索引中的所有字段类型,统统提前定义枚举好,那么以后往索引中加数据和字段时,就只能按照规定好的加。
如果加了类型不对等的数据,会报 400 错误。
二、核心概念
2.1索引(index)—库
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。可类比mysql中的数据库
2.2类型(type)—表,逐步弃用
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。 可类比mysql中的表
ElasticSearch6.0之后移除了类型的概念。7.x使用类型会警告,8.x将彻底废除。
2.3文档(document)—行
一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。 **插入索引库以文档为单位,类比与数据库中的一行数据
2.4字段(Filed)
相当于是数据表的字段,对文档数据根据不同属性进行的分类标识 。
三、物理设计
elasticsearch在后台把每个索引划分成多个分片,每分分片可以在集群中的不同服务器间迁移
一个人就是一个集群! ,即启动的ElasticSearch服务,默认就是一个集群,且默认集群名为elasticsearch
3.1集群cluster
一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由 一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集 群的名字,来加入这个集群。
3.2节点node
一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一 个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的 时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对 应于Elasticsearch集群中的哪些节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫 做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此, 它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点, 这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。
3.3分片和复制 shards&replicas
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因: 1)允许你水平分割/扩展你的内容容量。 2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,有两个主要原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。
创建新索引
一个集群至少有一个节点,而一个节点就是一个elasricsearch进程,节点可以有多个索引默认的,如果你创建索引,那么索引将会有个5个分片(primary shard ,又称主分片)构成的,每一个主分片会有一个副本(replica shard,又称复制分片)
上图是一个有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于失。实际上,一个分片是一个Lucene索引(一个ElasticSearch索引包含多个Lucene索引) ,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。不过,等等,倒排索引是什么鬼?
3.4倒排索引(Lucene索引底层)
简单说就是 按(文章关键字,对应的文档<0个或多个>)形式建立索引,根据关键字就可直接查询对应的文档(含关键字的),无需查询每一个文档,如下图
四、数据类型
4.1核心数据类型
4.1.1String类型
String类型可以和java的string、mysql的varchar等同,但是为何会分为text、keyword呢?这两者又有什么区别?
ES作为全文检索引擎,它强大的地方就在于分词和倒排序索引。而 text 和 keyword 的区别就在于是否分词(ps:什么叫分词?举个简单例子,“中国我爱你”这句话,如果使用了分词,那么这句话在底层的储存可能就是“中国”、“我爱你”,被拆分成了两个关键字)
4.1.1.2文本类型 - text
文本类型(Text):用于存储文本内容,支持全文搜索和分词等功能。例如,可以将文章的标题和正文存储为文本类型。
当一个字段需要用于全文搜索(会被分词), 比如产品名称、产品描述信息, 就应该使用text类型.
text 类型适用于需要被全文检索的字段,例如新闻正文、邮件内容等比较长的文字,text 类型会被 Lucene 分词器(Analyzer)处理为一个个词项,并使用 Lucene 倒排索引存储,text 字段不能被用于排序,如果需要使用该类型的字段只需要在定义映射时指定 JSON 中对应字段的 type 为 text。
text的内容会被分词, 可以设置是否需要存储:
"index": "true|false"
.
text类型的字段不能用于排序, 也很少用于聚合.
使用示例:
PUT website
{
"mappings": {
"blog": {
"properties": {
"summary": {"type": "text", "index": "true"}
}
}
}
}
4.1.1.3关键字类型 - keyword
keyword 适合简短、结构化字符串,例如主机名、姓名、商品名称等,可以用于过滤、排序、聚合检索,也可以用于精确查询。
当一个字段需要按照精确值进行过滤、排序、聚合等操作时, 就应该使用keyword类型.
keyword的内容不会被分词, 可以设置是否需要存储:
"index": "true|false"
.
PUT website
{
"mappings": {
"blog": {
"properties": {
"tags": {"type": "keyword", "index": "true"}
}
}
}
}
4.1.2数字类型
字类型分为 long、integer、short、byte、double、float、half_float、scaled_float。
数字类型的字段在满足需求的前提下应当尽量选择范围较小的数据类型,字段长度越短,搜索效率越高,对于浮点数,可以优先考虑使用 scaled_float 类型,该类型可以通过缩放因子来精确浮点数,例如 12.34 可以转换为 1234 来存储。
类型 | 说明 |
---|---|
byte | 有符号的8位整数, 范围: [-128 ~ 127] |
short | 有符号的16位整数, 范围: [-32768 ~ 32767] |
integer | 有符号的32位整数, 范围: [−2**31** ~ 231-1] |
long | 有符号的64位整数, 范围: [−2**63** ~ 263-1] |
float | 32位单精度浮点数 |
double | 64位双精度浮点数 |
half_float | 16位半精度IEEE 754浮点类型 |
scaled_float | 缩放类型的的浮点数, 比如price字段只需精确到分, 57.34缩放因子为100, 存储结果为5734 |
使用注意事项:
尽可能选择范围小的数据类型, 字段的长度越短, 索引和搜索的效率越高;
优先考虑使用带缩放因子的浮点类型.
使用示例:
PUT shop
{
"mappings": {
"book": {
"properties": {
"name": {"type": "text"},
"quantity": {"type": "integer"}, // integer类型
"price": {
"type": "scaled_float", // scaled_float类型
"scaling_factor": 100
}
}
}
}
}
4.1.3时间类型—date
在 ES 中日期可以为以下形式:
1、格式化的日期字符串,例如 2020-03-17 00:00、2020/03/17
2、时间戳(和 1970-01-01 00:00:00 UTC 的差值),单位毫秒或者秒
即使是格式化的日期字符串,ES 底层依然采用的是时间戳的形式存储。
JSON没有日期数据类型, 所以在ES中, 日期可以是:
- 包含格式化日期的字符串, “2018-10-01”, 或"2018/10/01 12:10:30".
- 代表时间毫秒数的长整型数字.
- 代表时间秒数的整数.
如果时区未指定, 日期将被转换为UTC格式, 但存储的却是长整型的毫秒值.
可以自定义日期格式, 若未指定, 则使用默认格式:strict_date_optional_time||epoch_millis
(1) 使用日期格式示例:
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"pub_date": {"type": "date"} // 日期类型
}
}
}
}
// 添加数据
PUT website/blog/11
{ "pub_date": "2018-10-10" }
PUT website/blog/12
{ "pub_date": "2018-10-10T12:00:00Z" } // Solr中默认使用的日期格式
PUT website/blog/13
{ "pub_date": "1589584930103" } // 时间的毫秒值
(2) 多种日期格式:
多个格式使用双竖线
||
分隔, 每个格式都会被依次尝试, 直到找到匹配的.
第一个格式用于将时间毫秒值转换为对应格式的字符串.
使用示例:
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"date": {
"type": "date", // 可以接受如下类型的格式
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
}
4.1.4布尔类型 - boolean
可以接受表示真、假的字符串或数字:
- 真值: true, “true”, “on”, “yes”, “1”…
- 假值: false, “false”, “off”, “no”, “0”, “”(空字符串), 0.0, 0
4.1.5二进制型 - binary
二进制类型是Base64编码字符串的二进制值, 不以默认的方式存储, 且不能被搜索. 有2个设置项:
(1)
doc_values
: 该字段是否需要存储到磁盘上, 方便以后用来排序、聚合或脚本查询. 接受true
和false
(默认);
(2)store
: 该字段的值是否要和_source
分开存储、检索, 意思是除了_source
中, 是否要单独再存储一份. 接受true
或false
(默认).
使用示例:
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"blob": {"type": "binary"} // 二进制
}
}
}
}
// 添加数据
PUT website/blog/1
{
"title": "Some binary blog",
"blob": "hED903KSrA084fRiD5JLgY=="
}
注意: Base64编码的二进制值不能嵌入换行符
\n
, 逗号(0x2c
)等符号.
4.1.6范围类型 - range
range类型支持以下几种:
类型 | 范围 |
---|---|
integer_range | −2**31** ~ 231−1 |
long_range | −2**63** ~ 263−1 |
float_range | 32位单精度浮点型 |
double_range | 64位双精度浮点型 |
date_range | 64位整数, 毫秒计时 |
ip_range | IP值的范围, 支持IPV4和IPV6, 或者这两种同时存在 |
(1) 添加映射:
PUT company
{
"mappings": {
"department": {
"properties": {
"expected_number": { // 预期员工数
"type": "integer_range"
},
"time_frame": { // 发展时间线
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"ip_whitelist": { // ip白名单
"type": "ip_range"
}
}
}
}
}
(2) 添加数据:
PUT company/department/1
{
"expected_number" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2018-10-01 12:00:00",
"lte" : "2018-11-01"
},
"ip_whitelist": "192.168.0.0/16"
}
(3) 查询数据:
GET company/department/_search
{
"query": {
"term": {
"expected_number": {
"value": 12
}
}
}
}
GET company/department/_search
{
"query": {
"range": {
"time_frame": {
"gte": "208-08-01",
"lte": "2018-12-01",
"relation": "within"
}
}
}
}
查询结果:
{
"took": 26,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.0,
"hits": [
{
"_index": "company",
"_type": "department",
"_id": "1",
"_score": 1.0,
"_source": {
"expected_number": {
"gte": 10,
"lte": 20
},
"time_frame": {
"gte": "2018-10-01 12:00:00",
"lte": "2018-11-01"
},
"ip_whitelist" : "192.168.0.0/16"
}
}
]
}
}
4.2复杂数据类型
4.2.1数组类型 - array
ES中没有专门的数组类型, 直接使用[]定义即可;
数组中所有的值必须是同一种数据类型, 不支持混合数据类型的数组:
① 字符串数组: [“one”, “two”];
② 整数数组: [1, 2];
③ 由数组组成的数组: [1, [2, 3]], 等价于[1, 2, 3];
④ 对象数组: [{“name”: “Tom”, “age”: 20}, {“name”: “Jerry”, “age”: 18}].
注意:
- 动态添加数据时, 数组中第一个值的类型决定整个数组的类型;
- 不支持混合数组类型, 比如[1, “abc”];
- 数组可以包含null值, 空数组[]会被当做missing field —— 没有值的字段.
在Elasticsearch中,没有专用的array数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值都必须具有相同的数据类型。
这一点是区别于nested的,nested指的对象的集合。而arrays则是单一类型的数组集合而已。
此外,不需要专门的类型类定义数组类型。
例如:
- 字符串数组
["one", "two"]
- 整数数组
[ 1,2]
- 数组的数组:
[ 1[ 2,3]]
,这是相当于[ 1,2,3]
动态添加字段时,数组中的第一个值确定field type。所有后续值必须具有相同的数据类型,或者至少必须能够将后续值强制转换为相同的数据类型。像[1, 3, "some word"]
不支持混合使用。
数组类型映射建立示例如下。
PUT example
PUT example/docs/_mapping
{
"properties": {
"id":{"type": "long"},
"name": {"type": "text"},
"age":{"type":"integer"},
"hobby": {"type": "text"}
}
}
注意:数组字段的定义,不是array哦。
数组类型的对象添加示例如下。
PUT example/docs/1
{
"id": 111,
"name":"张三",
"age":22,
"hobby":["篮球","摔跤"]
}
PUT example/docs/2
{
"id": 222,
"name":"张三2",
"age":21,
"hobby":["篮球222","摔跤222"]
}
数组类型的搜索示例如下。
#搜索爱好有篮球的
GET example/docs/_search
{
"query": {
"match": {
"hobby": "篮球"
}
}
}
# 最后搜出来2个结果
GET example/docs/_search
{
"query": {
"match": {
"hobby": "22"
}
}
}
# 最后搜出来1个结果
4.2.2对象类型 - object
JSON文档是分层的: 文档可以包含内部对象, 内部对象也可以包含内部对象.
(1) 添加示例:
PUT employee/developer/1
{
"name": "ma_shoufeng",
"address": {
"region": "China",
"location": {"province": "GuangDong", "city": "GuangZhou"}
}
}
(2) 存储方式:
{
"name": "ma_shoufeng",
"address.region": "China",
"address.location.province": "GuangDong",
"address.location.city": "GuangZhou"
}
(3) 文档的映射结构类似为:
PUT employee
{
"mappings": {
"developer": {
"properties": {
"name": { "type": "text", "index": "true" },
"address": {
"properties": {
"region": { "type": "keyword", "index": "true" },
"location": {
"properties": {
"province": { "type": "keyword", "index": "true" },
"city": { "type": "keyword", "index": "true" }
}
}
}
}
}
}
}
}
4.2.3嵌套类型 - nested
嵌套类型是对象数据类型的一个特例, 可以让array类型的对象被独立索引和搜索.
对象数组是如何存储的
① 添加数据:
PUT game_of_thrones/role/1
{
"group": "stark",
"performer": [
{"first": "John", "last": "Snow"},
{"first": "Sansa", "last": "Stark"}
]
}
② 内部存储结构:
{
"group": "stark",
"performer.first": [ "john", "sansa" ],
"performer.last": [ "snow", "stark" ]
}
③ 存储分析:
可以看出, user.first和user.last会被平铺为多值字段, 这样一来, John和Snow之间的关联性就丢失了.
在查询时, 可能出现John Stark的结果.
用nested类型解决object类型的不足
如果需要对以最对象进行索引, 且保留数组中每个对象的独立性, 就应该使用嵌套数据类型.
—— 嵌套对象实质是将每个对象分离出来, 作为隐藏文档进行索引.
① 创建映射:
PUT game_of_thrones
{
"mappings": {
"role": {
"properties": {
"performer": {"type": "nested" }
}
}
}
}
② 添加数据:
PUT game_of_thrones/role/1
{
"group" : "stark",
"performer" : [
{"first": "John", "last": "Snow"},
{"first": "Sansa", "last": "Stark"}
]
}
③ 检索数据:
GET game_of_thrones/_search
{
"query": {
"nested": {
"path": "performer",
"query": {
"bool": {
"must": [
{ "match": { "performer.first": "John" }},
{ "match": { "performer.last": "Snow" }}
]
}
},
"inner_hits": {
"highlight": {
"fields": {"performer.first": {}}
}
}
}
}
}
4.3地理数据类型
4.3.1地理点类型 - geo point
地理点类型用于存储地理位置的经纬度对, 可用于:
- 查找一定范围内的地理点;
- 通过地理位置或相对某个中心点的距离聚合文档;
- 将距离整合到文档的相关性评分中;
- 通过距离对文档进行排序.
(1) 添加映射:
PUT employee
{
"mappings": {
"developer": {
"properties": {
"location": {"type": "geo_point"}
}
}
}
}
(2) 存储地理位置:
// 方式一: 纬度 + 经度键值对
PUT employee/developer/1
{
"text": "小蛮腰-键值对地理点参数",
"location": {
"lat": 23.11, "lon": 113.33 // 纬度: latitude, 经度: longitude
}
}
// 方式二: "纬度, 经度"的字符串参数
PUT employee/developer/2
{
"text": "小蛮腰-字符串地理点参数",
"location": "23.11, 113.33" // 纬度, 经度
}
// 方式三: ["经度, 纬度"] 数组地理点参数
PUT employee/developer/3
{
"text": "小蛮腰-数组参数",
"location": [ 113.33, 23.11 ] // 经度, 纬度
}
(3) 查询示例:
GET employee/_search
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": { "lat": 24, "lon": 113 }, // 地理盒子模型的上-左边
"bottom_right": { "lat": 22, "lon": 114 } // 地理盒子模型的下-右边
}
}
}
}
4.3.2地理形状类型 - geo_shape
是多边形的复杂形状. 使用较少, 这里省略.
可以参考这篇文章: Elasticsearch地理位置总结
4.4专门数据类型
4.4.1IP类型
IP类型的字段用于存储IPv4或IPv6的地址, 本质上是一个长整型字段.
(1) 添加映射:
PUT employee
{
"mappings": {
"customer": {
"properties": {
"ip_addr": { "type": "ip" }
}
}
}
}
(2) 添加数据:
PUT employee/customer/1
{ "ip_addr": "192.168.1.1" }
(3) 查询数据:
GET employee/customer/_search
{
"query": {
"term": { "ip_addr": "192.168.0.0/16" }
}
}
4.4.2计数数据类型 - token_count
token_count类型用于统计字符串中的单词数量.
本质上是一个整数型字段, 接受并分析字符串值, 然后索引字符串中单词的个数.
(1) 添加映射:
PUT employee
{
"mappings": {
"customer": {
"properties": {
"name": {
"type": "text",
"fields": {
"length": {
"type": "token_count",
"analyzer": "standard"
}
}
}
}
}
}
}
(2) 添加数据:
PUT employee/customer/1
{ "name": "John Snow" }
PUT employee/customer/2
{ "name": "Tyrion Lannister" }
(3) 查询数据:
GET employee/customer/_search
{
"query": {
"term": { "name.length": 2 }
}
}