elasticsearch总结

admin 2022年1月6日01:34:43安全博客评论15 views29741字阅读99分8秒阅读模式

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。

详情看此文:http://wiki.jikexueyuan.com/project/elasticsearch-definitive-guide-cn/

0x1elasticsearch安装

到官网下载:https://www.elastic.co/cn/products/elasticsearch
ik分词器下载:
https://github.com/medcl/elasticsearch-analysis-ik/releases

0x1.1镜像拉取

1
docker pull elasticsearch:tag

0x1.2调高JVM线程数限制数量(不然启动容器的时候会报错,亲身试验)

1
2
3
4
5
vim /etc/sysctl.conf
# 添加这个
vm.max_map_count=262144
# 保存后执行这个命令
sysctl -p

0x1.3运行容器
ElasticSearch的默认端口是9200,我们把宿主环境9200端口映射到Docker容器中的9200端口,就可以访问到Docker容器中的ElasticSearch服务了,同时我们把这个容器命名为es。

1
docker run -it  -e "discovery.type=single-node" --name="es" -p 62100:9200 -p 63100:9300 elasticsearch:tag /bin/bash

0x1.4elasticsearch启动
以普通用户启动
https://blog.csdn.net/lahand/article/details/78954112
具体搭建以后再探讨
docker部署
https://juejin.im/post/5ca0d12c518825550b35be6d
https://blog.csdn.net/u014526891/article/details/82822647

0x2 elasticsearch简介

0x2.1Elasticsearch概念
Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它:

  • 分布式的实时文件存储,每个字段都被索引并可被搜索
  • 分布式的实时分析搜索引擎
  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

0x2.2集群和节点
节点(node)是一个运行着的Elasticsearch实例。集群(cluster)是一组具有相同cluster.name的节点集合,他们协同工作,共享数据并提供故障转移和扩展功能,当然一个节点也可以组成一个集群。

你最好找一个合适的名字来替代cluster.name的默认值,比如你自己的名字,这样可以防止一个新启动的节点加入到相同网络中的另一个同名的集群中。

你可以通过修改config/目录下的elasticsearch.yml文件,然后重启ELasticsearch来做到这一点。

0x2.3Java API
与Elasticsearch交互
如何与Elasticsearch交互取决于你是否使用Java。

Elasticsearch为Java用户提供了两种内置客户端:

节点客户端(node client):
节点客户端以无数据节点(none data node)身份加入集群,换言之,它自己不存储任何数据,但是它知道数据在集群中的具体位置,并且能够直接转发请求到对应的节点上。

传输客户端(Transport client):
这个更轻量的传输客户端能够发送请求到远程集群。它自己不加入集群,只是简单转发请求给集群中的节点。

两个Java客户端都通过9300端口与集群交互,使用Elasticsearch传输协议(Elasticsearch Transport Protocol)。集群中的节点之间也通过9300端口进行通信。如果此端口未开放,你的节点将不能组成集群。

TIP
Java客户端所在的Elasticsearch版本必须与集群中其他节点一致,否则,它们可能互相无法识别。

0x2.4基于HTTP协议,以JSON为数据交互格式的RESTful API
其他所有程序语言都可以使用RESTful API,通过9200端口的与Elasticsearch进行通信,你可以使用你喜欢的WEB客户端,事实上,如你所见,你甚至可以通过curl命令与Elasticsearch通信。

NOTE
Elasticsearch官方提供了多种程序语言的客户端——Groovy,Javascript, .NET,PHP,Perl,Python,以及 Ruby——还有很多由社区提供的客户端和插件,所有这些可以在文档中找到。

向Elasticsearch发出的请求的组成部分与其它普通的HTTP请求是一样的:

1
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'

VERB HTTP方法:GET, POST, PUT, HEAD, DELETE
PROTOCOL http或者https协议(只有在Elasticsearch前面有https代理的时候可用)
HOST Elasticsearch集群中的任何一个节点的主机名,如果是在本地的节点,那么就叫localhost
PORT Elasticsearch HTTP服务所在的端口,默认为9200
PATH API路径(例如_count将返回集群中文档的数量),PATH可以包含多个组件,例如_cluster/stats或者_nodes/stats/jvm
QUERY_STRING 一些可选的查询请求参数,例如?pretty参数将使请求返回更加美观易读的JSON数据
BODY 一个JSON格式的请求主体(如果请求需要的话)
举例说明,为了计算集群中的文档数量,我们可以这样做:

1
2
3
4
5
6
7
curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
"query": {
"match_all": {}
}
}
'

Elasticsearch返回一个类似200 OK的HTTP状态码和JSON格式的响应主体(除了HEAD请求)。上面的请求会得到如下的JSON格式的响应主体:

1
2
3
4
5
6
7
8
{
"count" : 0,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
}
}

0x2.5面向文档
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。这种理解数据的方式与以往完全不同,这也是Elasticsearch能够执行复杂的全文搜索的原因之一。

JSON
ELasticsearch使用Javascript对象符号(JavaScript Object Notation),也就是JSON,作为文档序列化格式。JSON现在已经被大多语言所支持,而且已经成为NoSQL领域的标准格式。它简洁、简单且容易阅读。

0x2.6索引
在Elasticsearch中,文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以画一些简单的对比图来类比传统关系型数据库:

1
2
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields

Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。

「索引」含义的区分
你可能已经注意到索引(index)这个词在Elasticsearch中有着不同的含义,所以有必要在此做一下区分:
索引(名词) 如上文所述,一个索引(index)就像是传统关系数据库中的数据库,它是相关文档存储的地方,index的复数是indices 或indexes。
索引(动词) 「索引一个文档」表示把一个文档存储到索引(名词)里,以便它可以被检索或者查询。这很像SQL中的INSERT关键字,差别是,如果文档已经存在,新的文档将覆盖旧的文档。
倒排索引 传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。Elasticsearch和Lucene使用一种叫做倒排索引(inverted index)的数据结构来达到相同目的。

0x2.7使用DSL语句查询
查询字符串搜索便于通过命令行完成特定(ad hoc)的搜索,但是它也有局限性(参阅简单搜索章节)。Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。

DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。我们可以这样表示之前关于“Smith”的查询:

1
2
3
4
5
6
7
8
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}

0x2.8聚合
最后,我们还有一个需求需要完成:允许管理者在职员目录中进行一些分析。 Elasticsearch有一个功能叫做聚合(aggregations),它允许你在数据上生成复杂的分析统计。它很像SQL中的GROUP BY但是功能更强大。

举个例子,让我们找到所有职员中最大的共同点(兴趣爱好)是什么:

1
2
3
4
5
6
7
8
GET /megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}

暂时先忽略语法只看查询结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
...
"hits": { ... },
"aggregations": {
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "forestry",
"doc_count": 1
},
{
"key": "sports",
"doc_count": 1
}
]
}
}
}

如果我们想知道所有姓”Smith”的人最大的共同点(兴趣爱好),我们只需要增加合适的语句既可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /megacorp/employee/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}

all_interests聚合已经变成只包含和查询语句相匹配的文档了:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "sports",
"doc_count": 1
}
]
}

聚合也允许分级汇总。例如,让我们统计每种兴趣下职员的平均年龄:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /megacorp/employee/_search
{
"aggs" : {
"all_interests" : {
"terms" : { "field" : "interests" },
"aggs" : {
"avg_age" : {
"avg" : { "field" : "age" }
}
}
}
}
}

虽然这次返回的聚合结果有些复杂,但任然很容易理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2,
"avg_age": {
"value": 28.5
}
},
{
"key": "forestry",
"doc_count": 1,
"avg_age": {
"value": 35
}
},
{
"key": "sports",
"doc_count": 1,
"avg_age": {
"value": 25
}
}
]
}

该聚合结果比之前的聚合结果要更加丰富。我们依然得到了兴趣以及数量(指具有该兴趣的员工人数)的列表,但是现在每个兴趣额外拥有avg_age字段来显示具有该兴趣员工的平均年龄。

0x2.9分布式系统
Elasticsearch致力于隐藏分布式系统的复杂性。以下这些操作都是在底层自动完成的:

  • 将你的文档分区到不同的容器或者分片(shards)中,它们可以存在于一个或多个节点中。
  • 将分片均匀的分配到各个节点,对索引和搜索做负载均衡。
  • 冗余每一个分片,防止硬件故障造成的数据丢失。
  • 将集群中任意一个节点上的请求路由到相应数据所在的节点。
  • 无论是增加节点,还是移除节点,分片都可以做到无缝的扩展和迁移。

0x3 分布式集群

0x3.1空集群
如果我们启动一个单独的节点,它还没有数据和索引
一个节点(node)就是一个Elasticsearch实例,而一个集群(cluster)由一个或多个节点组成,它们具有相同的cluster.name,它们协同工作,分享数据和负载。当加入新的节点或者删除一个节点时,集群就会感知到并平衡数据。

集群中一个节点会被选举为主节点(master),它将临时管理集群级别的一些变更,例如新建或删除索引、增加或移除节点等。主节点不参与文档级别的变更或搜索,这意味着在流量增长的时候,该主节点不会成为集群的瓶颈。任何节点都可以成为主节点。我们例子中的集群只有一个节点,所以它会充当主节点的角色。

做为用户,我们能够与集群中的任何节点通信,包括主节点。每一个节点都知道文档存在于哪个节点上,它们可以转发请求到相应的节点上。我们访问的节点负责收集各节点返回的数据,最后一起返回给客户端。这一切都由Elasticsearch处理。

0x3.2集群健康

在Elasticsearch集群中可以监控统计很多信息,但是只有一个是最重要的:集群健康(cluster health)。集群健康有三种状态:green、yellow或red。

1
GET /_cluster/health

在一个没有索引的空集群中运行如上查询,将返回这些信息:

1
2
3
4
5
6
7
8
9
10
11
12
{
"cluster_name": "elasticsearch",
"status": "green", <1>
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}

status 是我们最感兴趣的字段
status字段提供一个综合的指标来表示集群的的服务状况。三种颜色各自的含义:

颜色 意义
green 所有主要分片和复制分片都可用
yellow 所有主要分片可用,但不是所有复制分片都可用
red 不是所有的主要分片都可用

0x4 mapping

0x4.1字段类型

0x4.1.1.字符串

  • text : 文本,将会被分词
  • keyword : 有固定格式的文本,不会被分词(当作一个整体)

text类型一般用于全文索引,它将会被拆成多个关键词,与文档ID形成倒排索引,因此,在定义为text时,如果需要索引它,有必要指定它的分词器,特定是对于中文的文本 ,要自己制定iK分词器。
例子:
把full_name字段设为text类型的Mapping如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"title":{
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word",
"type": "text"
}
}
}
}
}

keyword类型适用于索引结构化的字段,比如email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合。keyword类型的字段只能通过精确值搜索到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"current_legal_status": {
"type": "text",
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
}
}
}
}
}

0x4.1.2数字类型

类型 取值范围
long -2^63至2^63-1
integer -2^31至2^31-1
short -32,768至32768
byte -128至127
double 64位双精度IEEE 754浮点类型
float 32位单精度IEEE 754浮点类型
half_float 16位半精度IEEE 754浮点类型
scaled_float 缩放类型的的浮点数(比如价格只需要精确到分,price为57.34的字段缩放因子为100,存起来就是5734)

对于float、half_float和scaled_float,-0.0和+0.0是不同的值,使用term查询查找-0.0不会匹配+0.0,同样range查询中上边界是-0.0不会匹配+0.0,下边界是+0.0不会匹配-0.0。

对于数字类型的数据,选择以上数据类型的注意事项:

  • 在满足需求的情况下,尽可能选择范围小的数据类型。比如,某个字段的取值最大值不会超过100,那么选择byte类型即可。迄今为止吉尼斯记录的人类的年龄的最大值为134岁,对于年龄字段,short足矣。字段的长度越短,索引和搜索的效率越高。
  • 优先考虑使用带缩放因子的浮点类型。

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"number_of_bytes": {
"type": "integer"
},
"time_in_seconds": {
"type": "float"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
}
}
}
}
}

0x4.1.3 Object类型
JSON天生具有层级关系,文档会包含嵌套的对象:

1
2
3
4
5
6
7
8
9
10
11
PUT my_index/my_type/1
{
"region": "US",
"manager": {
"age": 30,
"name": {
"first": "John",
"last": "Smith"
}
}
}

上面的文档中,整体是一个JSON,JSON中包含一个manager,manager又包含一个name。最终,文档会被索引成一平的key-value对:

1
2
3
4
5
6
{
"region": "US",
"manager.age": 30,
"manager.name.first": "John",
"manager.name.last": "Smith"
}

上面文档结构的Mapping如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"region": {
"type": "keyword"
},
"manager": {
"properties": {
"age": { "type": "integer" },
"name": {
"properties": {
"first": { "type": "text" },
"last": { "type": "text" }
}
}
}
}
}
}
}
}

0x4.1.4date类型
JSON中没有日期类型,所以在ELasticsearch中,日期类型可以是以下几种:

  • 日期格式的字符串:“2018-01-01” or “2018/01/01 12:10:30”.
  • long类型的毫秒数( milliseconds-since-the-epoch)
  • integer的秒数(seconds-since-the-epoch)

日期格式可以自定义,如果没有自定义,默认格式如下:

1
"strict_date_optional_time||epoch_millis"

范例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"publication_date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"

}
}
}
}
}

范例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"date": {
"type": "date"
}
}
}
}
}

PUT my_index/my_type/1
{ "date": "2015-01-01" }

PUT my_index/my_type/2
{ "date": "2015-01-01T12:10:30Z" }

PUT my_index/my_type/3
{ "date": 1420070400001 }

GET my_index/_search
{
"sort": { "date": "asc"}
}

查看三个日期类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "2",
"_score": 1,
"_source": {
"date": "2015-01-01T12:10:30Z"
}
},
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": 1,
"_source": {
"date": "2015-01-01"
}
},
{
"_index": "my_index",
"_type": "my_type",
"_id": "3",
"_score": 1,
"_source": {
"date": 1420070400001
}
}
]
}
}

0x4.1.5Array类型
ELasticsearch没有专用的数组类型,默认情况下任何字段都可以包含一个或者多个值,但是一个数组中的值要是同一种类型。例如:

  • 字符数组: [ “one”, “two” ]
  • 整型数组:[1,3]
  • 嵌套数组:[1,[2,3]],等价于[1,2,3]
  • 对象数组:[ { “name”: “Mary”, “age”: 12 }, { “name”: “John”, “age”: 10 }]

注意事项:

  • 动态添加数据时,数组的第一个值的类型决定整个数组的类型
  • 混合数组类型是不支持的,比如:[1,”abc”]
  • 数组可以包含null值,空数组[ ]会被当做missing field对待。

0x4.1.6布尔型boolean
逻辑类型(布尔类型)可以接受true/false/”true”/”false”值

1
2
3
4
5
6
7
8
9
10
PUT test
{
"mappings":{
"my":{
"properties": {
"empty":{"type":"boolean"}
}
}
}
}

一般范围类型,除了type属性外,还要有gte和lte两个附加参数
0x4.1.7binary类型
binary类型接受base64编码的字符串,默认不存储也不可搜索。
0x4.1.8ip类型
ip类型的字段用于存储IPV4或者IPV6的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"ip_addr": {
"type": "ip"
}
}
}
}
}

PUT my_index/my_type/1
{
"ip_addr": "192.168.1.1"
}

GET my_index/_search
{
"query": {
"term": {
"ip_addr": "192.168.0.0/16"
}
}
}

0x4.1.9range类型
一般范围类型,除了type属性外,还要有gte和lte两个附加参数

(1)数字范围

  • integer_range
  • long_range
  • float_range
  • double_range
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT user
{
"mappings": {
"_doc": {
"properties": {
"status": {
"type": "integer_range",
"gte": 0,
"lte":6
}
}
}
}
}

(2)日期范围
date_range
日期范围类型,可以附加一个format参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT user
{
"mappings": {
"_doc": {
"properties": {
"create_time": {
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss"
"get":"2019-03-30 10:00:00",
"lte":"2090-03-30 10:00:00"
}
}
}
}
}

range类型的使用场景:比如前端的时间选择表单、年龄范围选择表单等。
范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
PUT range_index
{
"mappings": {
"my_type": {
"properties": {
"expected_attendees": {
"type": "integer_range"
},
"time_frame": {
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
}

PUT range_index/my_type/1
{
"expected_attendees" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2015-10-31 12:00:00",
"lte" : "2015-11-01"
}
}

上面代码创建了一个range_index索引,expected_attendees的人数为10到20,时间是2015-10-31 12:00:00至2015-11-01。

查询:

1
2
3
4
5
6
7
8
9
10
11
12
POST range_index/_search
{
"query" : {
"range" : {
"time_frame" : {
"gte" : "2015-08-01",
"lte" : "2015-12-01",
"relation" : "within"
}
}
}
}

查询结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "range_index",
"_type": "my_type",
"_id": "1",
"_score": 1,
"_source": {
"expected_attendees": {
"gte": 10,
"lte": 20
},
"time_frame": {
"gte": "2015-10-31 12:00:00",
"lte": "2015-11-01"
}
}
}
]
}
}

0x4.1.10nested类型
nested嵌套类型是object中的一个特例,可以让array类型的Object独立索引和查询。 使用Object类型有时会出现问题,比如文档 my_index/my_type/1的结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PUT my_index/my_type/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}

user字段会被动态添加为Object类型。
最后会被转换为以下平整的形式:

1
2
3
4
5
6

{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}

user.first和user.last会被平铺为多值字段,Alice和White之间的关联关系会消失。上面的文档会不正确的匹配以下查询(虽然能搜索到,实际上不存在Alice Smith):

1
2
3
4
5
6
7
8
9
10
11
GET my_index/_search
{
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}

使用nested字段类型解决Object类型的不足:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
}

PUT my_index/my_type/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}

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

GET my_index/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "White" }}
]
}
},
"inner_hits": {
"highlight": {
"fields": {
"user.first": {}
}
}
}
}
}
}

0x4.1.11token_count类型
token_count用于统计词频:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"name": {
"type": "text",
"fields": {
"length": {
"type": "token_count",
"analyzer": "standard"
}
}
}
}
}
}
}

PUT my_index/my_type/1
{ "name": "John Smith" }

PUT my_index/my_type/2
{ "name": "Rachel Alice Williams" }

GET my_index/_search
{
"query": {
"term": {
"name.length": 3
}
}
}

0x4.1.12geo point
理位置信息类型用于存储地理位置信息的经纬度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
}

PUT my_index/my_type/1
{
"text": "Geo-point as an object",
"location": {
"lat": 41.12,
"lon": -71.34
}
}

PUT my_index/my_type/2
{
"text": "Geo-point as a string",
"location": "41.12,-71.34"
}

PUT my_index/my_type/3
{
"text": "Geo-point as a geohash",
"location": "drm3btev3e86"
}

PUT my_index/my_type/4
{
"text": "Geo-point as an array",
"location": [ -71.34, 41.12 ]
}

GET my_index/_search
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 42,
"lon": -72
},
"bottom_right": {
"lat": 40,
"lon": -74
}
}
}
}

}

0x4.2Meta-Fields(元数据)

0x4.2.1_all
_all字段是把其它字段拼接在一起的超级字段,所有的字段用空格分开,_all字段会被解析和索引,但是不存储。当你只想返回包含某个关键字的文档但是不明确地搜某个字段的时候就需要使用_all字段。
例子:

1
2
3
4
5
6
PUT my_index/blog/1 
{
"title": "Master Java",
"content": "learn java",
"author": "Tom"
}

_all字段包含:[ “Master”, “Java”, “learn”, “Tom” ]

搜索:

1
2
3
4
5
6
7
8
GET my_index/_search
{
"query": {
"match": {
"_all": "Java"
}
}
}

返回结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.39063013,
"hits": [
{
"_index": "my_index",
"_type": "blog",
"_id": "1",
"_score": 0.39063013,
"_source": {
"title": "Master Java",
"content": "learn java",
"author": "Tom"
}
}
]
}
}

使用copy_to自定义_all字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
PUT myindex
{
"mappings": {
"mytype": {
"properties": {
"title": {
"type": "text",
"copy_to": "full_content"
},
"content": {
"type": "text",
"copy_to": "full_content"
},
"full_content": {
"type": "text"
}
}
}
}
}

PUT myindex/mytype/1
{
"title": "Master Java",
"content": "learn Java"
}

GET myindex/_search
{
"query": {
"match": {
"full_content": "java"
}
}

}

0x4.2.2_field_names

_field_names字段用来存储文档中的所有非空字段的名字,这个字段常用于exists查询。例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT my_index/my_type/1
{
"title": "This is a document"
}

PUT my_index/my_type/2?refresh=true
{
"title": "This is another document",
"body": "This document has a body"
}

GET my_index/_search
{
"query": {
"terms": {
"_field_names": [ "body" ]
}
}
}

结果会返回第二条文档,因为第一条文档没有body字段。
同样,可以使用exists查询:

1
2
3
4
5
6
GET my_index/_search
{
"query": {
"exists" : { "field" : "body" }
}
}

0x4.2.3_id
每条被索引的文档都有一个_type和_id字段,_id可以用于term查询、temrs查询、match查询、query_string查询、simple_query_string查询,但是不能用于聚合、脚本和排序。例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PUT my_index/my_type/1
{
"text": "Document with ID 1"
}

PUT my_index/my_type/2
{
"text": "Document with ID 2"
}

GET my_index/_search
{
"query": {
"terms": {
"_id": [ "1", "2" ]
}
}
}

0x4.2.4_index
多索引查询时,有时候只需要在特地索引名上进行查询,_index字段提供了便利,也就是说可以对索引名进行term查询、terms查询、聚合分析、使用脚本和排序。

_index是一个虚拟字段,不会真的加到Lucene索引中,对_index进行term、terms查询(也包括match、query_string、simple_query_string),但是不支持prefix、wildcard、regexp和fuzzy查询。

举例,2个索引2条文档

1
2
3
4
5
6
7
8
9
PUT index_1/my_type/1
{
"text": "Document in index 1"
}

PUT index_2/my_type/2
{
"text": "Document in index 2"
}

对索引名做查询、聚合、排序并使用脚本新增字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
GET index_1,index_2/_search
{
"query": {
"terms": {
"_index": ["index_1", "index_2"]
}
},
"aggs": {
"indices": {
"terms": {
"field": "_index",
"size": 10
}
}
},
"sort": [
{
"_index": {
"order": "asc"
}
}
],
"script_fields": {
"index_name": {
"script": {
"lang": "painless",
"inline": "doc['_index']"
}
}
}
}

0x4.2.5_parent
_parent用于指定同一索引中文档的父子关系。下面例子中现在mapping中指定文档的父子关系,然后索引父文档,索引子文档时指定父id,最后根据子文档查询父文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
PUT my_index
{
"mappings": {
"my_parent": {},
"my_child": {
"_parent": {
"type": "my_parent"
}
}
}
}


PUT my_index/my_parent/1
{
"text": "This is a parent document"
}

PUT my_index/my_child/2?parent=1
{
"text": "This is a child document"
}

PUT my_index/my_child/3?parent=1&refresh=true
{
"text": "This is another child document"
}


GET my_index/my_parent/_search
{
"query": {
"has_child": {
"type": "my_child",
"query": {
"match": {
"text": "child document"
}
}
}
}
}

0x4.2.6_routing
路由参数,ELasticsearch通过以下公式计算文档应该分到哪个分片上:

1
shard_num = hash(_routing) % num_primary_shards

默认的_routing值是文档的_id或者_parent,通过_routing参数可以设置自定义路由。例如,想把user1发布的博客存储到同一个分片上,索引时指定routing参数,查询时在指定路由上查询:

1
2
3
4
5
6
PUT my_index/my_type/1?routing=user1&refresh=true 
{
"title": "This is a document"
}

GET my_index/my_type/1?routing=user1

在查询的时候通过routing参数查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET my_index/_search
{
"query": {
"terms": {
"_routing": [ "user1" ]
}
}
}

GET my_index/_search?routing=user1,user2
{
"query": {
"match": {
"title": "document"
}
}
}

在Mapping中指定routing为必须的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PUT my_index2
{
"mappings": {
"my_type": {
"_routing": {
"required": true
}
}
}
}

PUT my_index2/my_type/1
{
"text": "No routing value provided"

}

0x4.2.7 _source
_source
存储的文档的原始值。默认_source字段是开启的,也可以关闭:

1
2
3
4
5
6
7
8
9
10
PUT tweets
{
"mappings": {
"tweet": {
"_source": {
"enabled": false
}
}
}
}

但是一般情况下不要关闭,除法你不想做一些操作:

  • 使用update、update_by_query、reindex
  • 使用高亮
  • 数据备份、改变mapping、升级索引
  • 通过原始字段debug查询或者聚合

0x4.3Mapping参数

0x4.3.1analyzer
指定分词器(分析器更合理),对索引和查询都有效。如下,指定ik分词的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}
}

}

0x4.3.2normalizer
normalizer用于解析前的标准化配置,比如把所有的字符转化为小写等。例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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经过normalizer过滤以后转换为bar,文档1和文档2会被搜索到。

0x4.3.3boost
boost字段用于设置字段的权重,比如,关键字出现在title字段的权重是出现在content字段中权重的2倍,设置mapping如下,其中content字段的默认权重是1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "text",
"boost": 2
},
"content": {
"type": "text"
}
}
}
}
}

同样,在查询时指定权重也是一样的:

1
2
3
4
5
6
7
8
9
10
11
POST _search
{
"query": {
"match" : {
"title": {
"query": "quick brown fox",
"boost": 2
}
}
}
}

0x4.3.4coerce
coerce属性用于清除脏数据,coerce的默认值是true。整型数字5有可能会被写成字符串“5”或者浮点数5.0.coerce属性可以用来清除脏数据:

字符串会被强制转换为整数
浮点数被强制转换为整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"number_one": {
"type": "integer"
},
"number_two": {
"type": "integer",
"coerce": false
}
}
}
}
}

PUT my_index/my_type/1
{
"number_one": "10"
}

PUT my_index/my_type/2
{
"number_two": "10"
}

mapping中指定number_one字段是integer类型,虽然插入的数据类型是String,但依然可以插入成功。number_two字段关闭了coerce,因此插入失败。

0x4.3.5copy_to
copy_to属性用于配置自定义的_all字段。换言之,就是多个字段可以合并成一个超级字段。比如,first_name和last_name可以合并为full_name字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"first_name": {
"type": "text",
"copy_to": "full_name"
},
"last_name": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
}
}
}

PUT my_index/my_type/1
{
"first_name": "John",
"last_name": "Smith"
}

GET my_index/_search
{
"query": {
"match": {
"full_name": {
"query": "John Smith",
"operator": "and"
}
}
}
}

0x4.3.6doc_values
doc_values是为了加快排序、聚合操作,在建立倒排索引的时候,额外增加一个列式存储映射,是一个空间换时间的做法。默认是开启的,对于确定不需要聚合或者排序的字段可以关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"status_code": {
"type": "keyword"
},
"session_id": {
"type": "keyword",
"doc_values": false
}
}
}
}
}

0x4.3.7dynamic
dynamic属性用于检测新发现的字段,有三个取值:

  • true:新发现的字段添加到映射中。(默认)
  • flase:新检测的字段被忽略。必须显式添加新字段。
  • strict:如果检测到新字段,就会引发异常并拒绝文档。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PUT my_index
{
"mappings": {
"my_type": {
"dynamic": false,
"properties": {
"user": {
"properties": {
"name": {
"type": "text"
},
"social_networks": {
"dynamic": true,
"properties": {}
}
}
}
}
}
}

}

PS:取值为strict,非布尔值要加引号
0x4.3.8enabled
ELasticseaech默认会索引所有的字段,enabled设为false的字段,es会跳过字段内容,该字段只能从_source中获取,但是不可搜。而且字段可以是任意类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
PUT my_index
{
"mappings": {
"session": {
"properties": {
"user_id": {
"type": "keyword"
},
"last_updated": {
"type": "date"
},
"session_data": {
"enabled": false
}
}
}
}
}

PUT my_index/session/session_1
{
"user_id": "kimchy",
"session_data": {
"arbitrary_object": {
"some_array": [ "foo", "bar", { "baz": 2 } ]
}
},
"last_updated": "2015-12-06T18:20:22"
}

PUT my_index/session/session_2
{
"user_id": "jpountz",
"session_data": "none",
"last_updated": "2015-12-06T18:22:13"
}

0x4.3.9fielddata
搜索要解决的问题是“包含查询关键词的文档有哪些?”,聚合恰恰相反,聚合要解决的问题是“文档包含哪些词项”,大多数字段再索引时生成doc_values,但是text字段不支持doc_values。

取而代之,text字段在查询时会生成一个fielddata的数据结构,fielddata在字段首次被聚合、排序、或者使用脚本的时候生成。ELasticsearch通过读取磁盘上的倒排记录表重新生成文档词项关系,最后在Java堆内存中排序。

text字段的fielddata属性默认是关闭的,开启fielddata非常消耗内存。在你开启text字段以前,想清楚为什么要在text类型的字段上做聚合、排序操作。大多数情况下这么做是没有意义的。

“New York”会被分析成“new”和“york”,在text类型上聚合会分成“new”和“york”2个桶,也许你需要的是一个“New York”。这是可以加一个不分析的keyword字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"my_field": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
}

面的mapping中实现了通过my_field字段做全文搜索,my_field.keyword做聚合、排序和使用脚本。
0x4.3.10 ignore_above
ignore_above用于指定字段索引和存储的长度最大值,超过最大值的会被忽略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"message": {
"type": "keyword",
"ignore_above": 15
}
}
}
}
}

PUT my_index/my_type/1
{
"message": "Syntax error"
}

PUT my_index/my_type/2
{
"message": "Syntax error with some long stacktrace"
}

GET my_index/_search
{
"size": 0,
"aggs": {
"messages": {
"terms": {
"field": "message"
}
}
}
}

mapping中指定了ignore_above字段的最大长度为15,第一个文档的字段长小于15,因此索引成功,第二个超过15,因此不索引,返回结果只有”Syntax error”,结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0,
"hits": []
},
"aggregations": {
"messages": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": []
}
}
}

0x4.3.11ignore_malformed
ignore_malformed可以忽略不规则数据,对于login字段,有人可能填写的是date类型,也有人填写的是邮件格式。给一个字段索引不合适的数据类型发生异常,导致整个文档索引失败。如果ignore_malformed参数设为true,异常会被忽略,出异常的字段不会被索引,其它字段正常索引。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"number_one": {
"type": "integer",
"ignore_malformed": true
},
"number_two": {
"type": "integer"
}
}
}
}
}

PUT my_index/my_type/1
{
"text": "Some text value",
"number_one": "foo"
}

PUT my_index/my_type/2
{
"text": "Some text value",
"number_two": "foo"
}

上面的例子中number_one接受integer类型,ignore_malformed属性设为true,因此文档一种number_one字段虽然是字符串但依然能写入成功;number_two接受integer类型,默认ignore_malformed属性为false,因此写入失败。

0x4.3.12format
format属性主要用于格式化日期:

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
}

0x4.3.13include_in_all
include_in_all属性用于指定字段是否包含在_all字段里面,默认开启,除索引时index属性为no。
例子如下,title和content字段包含在_all字段里,date不包含。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
},
"date": {
"type": "date",
"include_in_all": false
}
}
}
}
}

include_in_all也可用于字段级别,如下my_type下的所有字段都排除在_all字段之外,author.first_name 和author.last_name 包含在in _all中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PUT my_index
{
"mappings": {
"my_type": {
"include_in_all": false,
"properties": {
"title": { "type": "text" },
"author": {
"include_in_all": true,
"properties": {
"first_name": { "type": "text" },
"last_name": { "type": "text" }
}
},
"editor": {
"properties": {
"first_name": { "type": "text" },
"last_name": { "type": "text", "include_in_all": true }
}
}
}
}
}
}

0x4.3.14index
index属性指定字段是否索引,不索引也就不可搜索,取值可以为true或者false。

0x4.3.15index_options
index_options控制索引时存储哪些信息到倒排索引中,接受以下配置:

参数 作用
docs 只存储文档编号
freqs 存储文档编号和词项频率
positions 文档编号、词项频率、词项的位置被存储,偏移位置可用于临近搜索和短语查询
offsets 文档编号、词项频率、词项的位置、词项开始和结束的字符位置都被存储,offsets设为true会使用Postings highlighter

0x4.3.16 fields
fields可以让同一文本有多种不同的索引方式,比如一个String类型的字段,可以使用text类型做全文检索,使用keyword类型做聚合和排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
}

PUT my_index/my_type/1
{
"city": "New York"
}

PUT my_index/my_type/2
{
"city": "York"
}

GET my_index/_search
{
"query": {
"match": {
"city": "york"
}
},
"sort": {
"city.raw": "asc"
},
"aggs": {
"Cities": {
"terms": {
"field": "city.raw"
}
}
}
}
**0x4.3.17 norms**
norms参数用于标准化文档,以便查询时计算文档的相关性。norms虽然对评分有用,但是会消耗较多的磁盘空间,如果不需要对某个字段进行评分,最好不要开启norms。

**0x4.3.18 null_value**
值为null的字段不索引也不可以搜索,null_value参数可以让值为null的字段显式的可索引、可搜索。例子:
```bash
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"status_code": {
"type": "keyword",
"null_value": "NULL"
}
}
}
}
}

PUT my_index/my_type/1
{
"status_code": null
}

PUT my_index/my_type/2
{
"status_code": []
}

GET my_index/_search
{
"query": {
"term": {
"status_code": "NULL"
}
}
}

文档1可以被搜索到,因为status_code的值为null,文档2不可以被搜索到,因为status_code为空数组,但是不是null。

0x4.3.19 position_increment_gap
为了支持近似或者短语查询,text字段被解析的时候会考虑此项的位置信息。举例,一个字段的值为数组类型:

1
"names": [ "John Abraham", "Lincoln Smith"]

为了区别第一个字段和第二个字段,Abraham和Lincoln在索引中有一个间距,默认是100。例子如下,这是查询”Abraham Lincoln”是查不到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT my_index/groups/1
{
"names": [ "John Abraham", "Lincoln Smith"]
}

GET my_index/groups/_search
{
"query": {
"match_phrase": {
"names": {
"query": "Abraham Lincoln"
}
}
}
}

指定间距大于100可以查询到:

1
2
3
4
5
6
7
8
9
10
11
GET my_index/groups/_search
{
"query": {
"match_phrase": {
"names": {
"query": "Abraham Lincoln",
"slop": 101
}
}
}
}

在mapping中通过position_increment_gap参数指定间距:

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT my_index
{
"mappings": {
"groups": {
"properties": {
"names": {
"type": "text",
"position_increment_gap": 0
}
}
}
}
}

0x4.3.20 properties
Object或者nested类型,下面还有嵌套类型,可以通过properties参数指定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"manager": {
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
},
"employees": {
"type": "nested",
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
}
}
}
}
}

对应的文档结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PUT my_index/my_type/1 
{
"region": "US",
"manager": {
"name": "Alice White",
"age": 30
},
"employees": [
{
"name": "John Smith",
"age": 34
},
{
"name": "Peter Brown",
"age": 26
}
]
}

可以对manager.name、manager.age做搜索、聚合等操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GET my_index/_search
{
"query": {
"match": {
"manager.name": "Alice White"
}
},
"aggs": {
"Employees": {
"nested": {
"path": "employees"
},
"aggs": {
"Employee Ages": {
"histogram": {
"field": "employees.age",
"interval": 5
}
}
}
}
}
}

0x4.3.21 search_analyzer
大多数情况下索引和搜索的时候应该指定相同的分析器,确保query解析以后和索引中的词项一致。但是有时候也需要指定不同的分析器,例如使用edge_ngram过滤器实现自动补全。

默认情况下查询会使用analyzer属性指定的分析器,但也可以被search_analyzer覆盖。例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
PUT my_index
{
"settings": {
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
"mappings": {
"my_type": {
"properties": {
"text": {
"type": "text",
"analyzer": "autocomplete",
"search_analyzer": "standard"
}
}
}
}
}

PUT my_index/my_type/1
{
"text": "Quick Brown Fox"
}

GET my_index/_search
{
"query": {
"match": {
"text": {
"query": "Quick Br",
"operator": "and"
}
}
}
}

0x4.3.22 similarity
similarity参数用于指定文档评分模型,参数有三个:

BM25 :ES和Lucene默认的评分模型
classic :TF/IDF评分
boolean:布尔模型评分
例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"default_field": {
"type": "text"
},
"classic_field": {
"type": "text",
"similarity": "classic"
},
"boolean_sim_field": {
"type": "text",
"similarity": "boolean"
}
}
}
}
}

default_field自动使用BM25评分模型,classic_field使用TF/IDF经典评分模型,boolean_sim_field使用布尔评分模型。

0x4.3.23 store
默认情况下,自动是被索引的也可以搜索,但是不存储,这也没关系,因为_source字段里面保存了一份原始文档。在某些情况下,store参数有意义,比如一个文档里面有title、date和超大的content字段,如果只想获取title和date,可以这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "text",
"store": true
},
"date": {
"type": "date",
"store": true
},
"content": {
"type": "text"
}
}
}
}
}

PUT my_index/my_type/1
{
"title": "Some short title",
"date": "2015-01-01",
"content": "A very long content field..."
}

GET my_index/_search
{
"stored_fields": [ "title", "date" ]
}

查询结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": 1,
"fields": {
"date": [
"2015-01-01T00:00:00.000Z"
],
"title": [
"Some short title"
]
}
}
]
}
}
```
Stored fields返回的总是数组,如果想返回原始字段,还是要从_source中取。

**0x4.3.24 term_vector**
词向量包含了文本被解析以后的以下信息:

词项集合
词项位置
词项的起始字符映射到原始文档中的位置。
term_vector参数有以下取值:

参数取值 含义
no 默认值,不存储词向量
yes 只存储词项集合
with_positions 存储词项和词项位置
with_offsets 词项和字符偏移位置
with_positions_offsets 存储词项、词项位置、字符偏移位置
例子:
```bash
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"text": {
"type": "text",
"term_vector": "with_positions_offsets"
}
}
}
}
}

PUT my_index/my_type/1
{
"text": "Quick brown fox"
}

GET my_index/_search
{
"query": {
"match": {
"text": "brown fox"
}
},
"highlight": {
"fields": {
"text": {}
}
}

}

0x5 elasticsearch操作

参考文章:
http://wiki.jikexueyuan.com/project/elasticsearch-definitive-guide-cn/
http://www.shixinke.com/
ES Mapping、字段类型Field type详解https://blog.csdn.net/ZYC88888/article/details/83059040

FROM :blog.cfyqy.com | Author:cfyqy

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:34:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  elasticsearch总结 http://cn-sec.com/archives/721874.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: