ElasticSearch 进阶

ElasticSearch 进阶

1.重要的配置

理想情况下,Elasticsearch 应该在服务器上单独运行并使用所有可用资源。

在投入生产之前,必须解决以下设置:

一旦您配置了类似 的网络设置network.host,Elasticsearch 就会假定您正在进入生产环境,并将上述警告升级为异常。这些异常将阻止您的 Elasticsearch 节点启动。

1.JVM 配置

  • 将最小堆大小 (Xms) 和最大堆大小 (Xmx) 设置为彼此相等。

  • Elasticsearch 可用的堆越多,它可用于缓存的内存就越多。但请注意,过多的堆会使您遭受长时间的垃圾收集暂停。

  • 将 Xmx 设置为不超过物理 RAM 的 50%,以确保有足够的物理 RAM 用于内核文件系统缓存。

  • 不要将 Xmx 设置为高于 JVM 用于压缩对象指针(压缩 oops)的截止值;确切的截止值有所不同,但接近 32 GB

    config/jvm.options

- Xms31g 
- Xmx31g

禁用交换:

bootstrap.memory_lock: true

2.查询交换:

交换区可能会导致部分 JVM 堆甚至其可执行页面被换出到磁盘。

交换对性能和节点稳定性非常不利免。可能导致垃圾收集持续几分钟而不是几毫秒,并可能导致节点响应缓慢甚至与集群断开连接。在弹性分布式系统中,让操作系统杀死节点更有效。

curl -X GET "localhost:9200/_nodes?filter_path=**.mlockall&pretty"
# Kibana
GET _nodes?filter_path=**.mlockall

3.增加文件描述符

Elasticsearch 使用了很多文件描述符或文件句柄。耗尽文件描述符可能是灾难性的,并且很可能会导致数据丢失。

set nofile to 65536 in /etc/security/limits.conf

查询:

curl -X GET "localhost:9200/_nodes/stats/process?filter_path=**.max_file_descriptors&pretty"
# Kibana
GET _nodes/stats/process?filter_path=**.max_file_descriptors

4.增加虚拟内存

Elasticsearchmmapfs默认使用一个目录来存储它的索引。操作系统对 mmap 计数的默认限制可能太低,这可能会导致内存不足异常。

vim /etc/sysctl.conf

修改

vm.max_map_count=262144

要在重新启动后进行验证,请运行sysctl vm.max_map_count.

5.增加线程数

vim /etc/security/limits.conf
# 设置 nproc 至少为4096

6.DNS缓存设置

Elasticsearch 运行时有一个安全管理器。有了安全管理器,JVM 默认会无限期地缓存正主机名解析。如果您的 Elasticsearch 节点在 DNS 解析随时间变化的环境中依赖 DNS(例如,对于节点到节点的发现),那么您可能需要修改默认的 JVM 行为。这可以通过添加networkaddress.cache.ttl= 到您的 Java 安全策略来修改 。任何无法解析的主机都将被记录。另请注意,在 Java 安全管理器到位后,JVM 默认将负面主机名解析缓存十秒钟。这可以通过添加networkaddress.cache.negative.ttl= 到您的 Java 安全策略来修改 。

引导检查

可以通过将系统属性设置es.enforce.bootstrap.checkstrue,强制执行引导程序检查。

API 约定

本章中列出的约定可应用于整个 REST API。

1.多个索引

大多数引用index参数的API支持跨多个索引执行。表示方法有:

1.test1,test2,test3
2._all
3.通配符,test*or*testte*tor *test*,以及“排除” (-),例如:test*,-test3

单索引 API,如文档 API单索引aliasAPI,不支持多索引。

2.索引名称中的日期数学支持

几乎所有具有index参数的API 都支持index参数值中的日期数学。

\反斜杠代表转义

<static_name{date_math_expr{date_format|time_zone}}>
关键字 含义
static_name 是名称的静态文本部分
date_math_expr 是动态计算日期的动态日期数学表达式
date_format 是计算日期应呈现的可选格式。默认为YYYY.MM.dd.
time_zone 是可选的时区。默认为utc.

必须将日期数学索引名称表达式括在尖括号内,并且所有特殊字符都应进行 URI 编码。例如

# GET /<logstash-{now/d}>/_search
curl -X GET "localhost:9200/%3Clogstash-%7Bnow%2Fd%7D%3E/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query" : {
    "match": {
      "test": "data"
    }
  }
}
'

# Kibana
# GET /<logstash-{now/d}>/_search
GET /%3Clogstash-%7Bnow%2Fd%7D%3E/_search
{
  "query" : {
    "match": {
      "test": "data"
    }
  }
}

日期数学字符的百分号编码

< %3C
> %3E
/ %2F
{ %7B
} %7D
| %7C
+ %2B
: %3A
, %2C

以下示例显示了不同形式的日期数学索引名称以及它们解析为给定当前时间是 2024 年 3 月 22 日中午 utc 的最终索引名称。

表达式 解决为
<logstash-{now/d}> logstash-2024.03.22
<logstash-{now/M}> logstash-2024.03.01
<logstash-{now/M{YYYY.MM}}> logstash-2024.03
<logstash-{now/M-1M{YYYY.MM}}> logstash-2024.02
<logstash-{now/d{YYYY.MM.dd|+12:00}}> logstash-2024.03.23

以下示例显示了搜索过去三天的 Logstash 索引的搜索请求,假设索引使用默认的 Logstash 索引名称格式 logstash-YYYY.MM.dd.

# GET /<logstash-{now/d-2d}>,<logstash-{now/d-1d}>,<logstash-{now/d}>/_search
curl -X GET "hadoop102:9200/%3Clogstash-%7Bnow%2Fd-2d%7D%3E%2C%3Clogstash-%7Bnow%2Fd-1d%7D%3E%2C%3Clogstash-%7Bnow%2Fd%7D%3E/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query" : {
    "match": {
      "test": "data"
    }
  }
}
'

# Kibana
# GET /<logstash-{now/d-2d}>,<logstash-{now/d-1d}>,<logstash-{now/d}>/_search
GET /%3Clogstash-%7Bnow%2Fd-2d%7D%3E%2C%3Clogstash-%7Bnow%2Fd-1d%7D%3E%2C%3Clogstash-%7Bnow%2Fd%7D%3E/_search
{
  "query" : {
    "match": {
      "test": "data"
    }
  }
}

REST API 常用参数

以下选项可应用于所有 REST API。

1.?pretty=true

当附加?pretty=true到任何请求时,返回的 JSON 将被格式化(仅用于调试!)。另一个选项是设置?format=yaml这将导致以(有时)更易读的 yaml 格式返回结果。

2.?human=false

统计数据以适合人类(例如"exists_time": "1h""size": "1kb")和计算机(例如"exists_time_in_millis": 3600000"size_in_bytes": 1024)的格式返回。可以通过添加?human=false 到查询字符串来关闭人类可读的值。当统计结果被监控工具使用而不是供人类使用时,这是有道理的。human标志的默认值是 false

3.日期数学

假设now2001-01-01 12:00:00,一些例子是:

  • now+1h

    now以毫秒为单位加一小时。解决为:2001-01-01 13:00:00

  • now-1h

    now以毫秒为单位减去一小时。解决为:2001-01-01 11:00:00

  • now-1h/d

    now以毫秒为单位减去一小时,向下舍入到 UTC 00:00。解决为:`2001-01-01 00:00:00``

  • 2001-01-01\|\|+1M/d

    now以毫秒为单位加一个月。解决为:2001-02-01 00:00:00

所有 REST API 都接受一个filter_path参数

例子1:

curl -X GET "localhost:9200/_search?q=elasticsearch&filter_path=took,hits.hits._id,hits.hits._score&pretty"

# Kibana
GET /_search?q=elasticsearch&filter_path=took,hits.hits._id,hits.hits._score

结果:

{
  "took" : 3,
  "hits" : {
    "hits" : [
      {
        "_id" : "0",
        "_score" : 1.6375021
      }
    ]
  }
}

例子2:*通配符来匹配任何字段或字段名称的一部分:

curl -X GET "localhost:9200/_cluster/state?filter_path=metadata.indices.*.stat*&pretty"
# Kibana
GET /_cluster/state?filter_path=metadata.indices.*.stat*

结果:

{
  "metadata" : {
    "indices" : {
      "twitter": {"state": "open"}
    }
  }
}

例子3: 并且**通配符可用于在不知道字段的确切路径的情况下包含字段。例如,我们可以通过此请求返回每个段的 Lucene 版本:

curl -X GET "localhost:9200/_cluster/state?filter_path=routing_table.indices.**.state&pretty"
# Kibana
GET /_cluster/state?filter_path=routing_table.indices.**.state

结果:

{
  "routing_table": {
    "indices": {
      "twitter": {
        "shards": {
          "0": [{"state": "STARTED"}, {"state": "UNASSIGNED"}],
          "1": [{"state": "STARTED"}, {"state": "UNASSIGNED"}],
          "2": [{"state": "STARTED"}, {"state": "UNASSIGNED"}],
          "3": [{"state": "STARTED"}, {"state": "UNASSIGNED"}],
          "4": [{"state": "STARTED"}, {"state": "UNASSIGNED"}]
        }
      }
    }
  }
}

例子4:也可以通过在过滤器前加上 char 来排除一个或多个字段-

curl -X GET "localhost:9200/_count?filter_path=-_shards&pretty"

# Kibana
GET /_count?filter_path=-_shards

结果:

{
  "count" : 5
}

例子5:为了获得更多控制,可以在同一个表达式中组合包含和排除过滤器。在这种情况下,将首先应用独占过滤器,然后使用包含过滤器再次过滤结果:

curl -X GET "localhost:9200/_cluster/state?filter_path=metadata.indices.*.state,-metadata.indices.logstash-*&pretty"

# Kibana
GET /_cluster/state?filter_path=metadata.indices.*.state,-metadata.indices.logstash-*

结果:

{
  "metadata" : {
    "indices" : {
      "index-1" : {"state" : "open"},
      "index-2" : {"state" : "open"},
      "index-3" : {"state" : "open"}
    }
  }
}

例子6:Elasticsearch 有时会直接返回字段的原始值,例如_source字段。如果要过滤_source字段,应考虑将现有_source参数与如下filter_path 参数组合使用:

curl -X POST "localhost:9200/library/book?refresh&pretty" -H 'Content-Type: application/json' -d'
{"title": "Book #1", "rating": 200.1}
'
curl -X POST "localhost:9200/library/book?refresh&pretty" -H 'Content-Type: application/json' -d'
{"title": "Book #2", "rating": 1.7}
'
curl -X POST "localhost:9200/library/book?refresh&pretty" -H 'Content-Type: application/json' -d'
{"title": "Book #3", "rating": 0.1}
'
curl -X GET "localhost:9200/_search?filter_path=hits.hits._source&_source=title&sort=rating:desc&pretty"


# Kibana
POST /library/book?refresh
{"title": "Book #1", "rating": 200.1}
POST /library/book?refresh
{"title": "Book #2", "rating": 1.7}
POST /library/book?refresh
{"title": "Book #3", "rating": 0.1}
GET /_search?filter_path=hits.hits._source&_source=title&sort=rating:desc

结果:

例子7:该flat_settings标志影响设置列表的呈现。当 flat_settings标志是以true平面格式返回设置时:

curl -X GET "localhost:9200/twitter/_settings?flat_settings=true&pretty"

# Kibana
GET twitter/_settings?flat_settings=true

结果:

{
  "twitter" : {
    "settings": {
      "index.number_of_replicas": "1",
      "index.number_of_shards": "1",
      "index.creation_date": "1474389951325",
      "index.uuid": "n6gzFZTgS664GUfx0Xrpjw",
      "index.version.created": ...,
      "index.provided_name" : "twitter"
    }
  }
}

例子8:当flat_settings标志是false设置以更易读的结构化格式返回时:

默认情况下flat_settings设置为false

curl -X GET "localhost:9200/twitter/_settings?flat_settings=false&pretty"

# Kibana
GET twitter/_settings?flat_settings=false

结果:

{
  "twitter" : {
    "settings" : {
      "index" : {
        "number_of_replicas": "1",
        "number_of_shards": "1",
        "creation_date": "1474389951325",
        "uuid": "n6gzFZTgS664GUfx0Xrpjw",
        "version": {
          "created": ...
        },
        "provided_name" : "twitter"
      }
    }
  }
}

4.参数

其余参数(使用 HTTP 时,映射到 HTTP URL 参数)遵循使用下划线大小写的约定。

5.布尔值

所有 REST API 参数(请求参数和 JSON 正文)都支持提供布尔值“false”作为值false和布尔值“true”作为值true。所有其他值都会引发错误。

6.数值

除了string支持本机 JSON 数字类型之外,所有 REST API 都支持提供编号参数。

7.时间单位

每当需要指定持续时间时,例如对于timeout参数,持续时间必须指定单位,例如2d2 天。支持的单位有:

d
h 小时
m 分钟
s
ms 毫秒
micros 微秒
nanos 纳秒

8.启用堆栈跟踪 error_trace

curl -X POST "localhost:9200/twitter/_search?size=surprise_me&error_trace=true&pretty"

# Kibana
POST /twitter/_search?size=surprise_me&error_trace=true

结果:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "Failed to parse int parameter [size] with value [surprise_me]",
        "stack_trace": "Failed to parse int parameter [size] with value [surprise_me]]; nested: IllegalArgumentException..."
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Failed to parse int parameter [size] with value [surprise_me]",
    "stack_trace": "java.lang.IllegalArgumentException: Failed to parse int parameter [size] with value [surprise_me]\n    at org.elasticsearch.rest.RestRequest.paramAsInt(RestRequest.java:175)...",
    "caused_by": {
      "type": "number_format_exception",
      "reason": "For input string: \"surprise_me\"",
      "stack_trace": "java.lang.NumberFormatException: For input string: \"surprise_me\"\n    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)..."
    }
  },
  "status": 400
}

2.Document API

本节首先简要介绍 Elasticsearch 的数据副本模型,然后详细描述以下 CRUD API:

单文档 API

多文档 API

所有 CRUD API 都是单索引 API。该index参数接受单个索引名称,或alias指向单个索引的an 。

1.读和写 document

介绍

routing:通过 id 读写 document 时,先路由到主分片,主分片进行读写操作一致性的保证。

副本组replication group):每个 index 包含多个 shard,每个 shard 会有多个副本,这个副本称为副本组,包括 primary 副本 和 replica副本,副本组有主分片和副本分片;

基本写入模型

Elasticsearch 中的每个索引操作首先使用routing解析为复制组,通常基于文档 ID。

一旦确定了复制组,操作就会在内部转发到该组的当前主分片*。

主分片负责验证操作并将其转发到其他副本,字段类型不匹配等。

es 维护一个同步副本列表(官网:in-sync replica),所有同步列表复制完成写操作。

主分片遵循以下基本流程:

  1. 结构上验证写操作,无效时拒绝(例如:有一个需要数字的对象字段)
  2. 在本地执行操作,即索引或删除相关文档。这也将验证字段的内容并在需要时拒绝(例如:关键字值对于 Lucene 中的索引而言太长)。
  3. 将操作转发到当前同步副本列表中的每个副本。多个副本并行完成的(不是所有副本,而是主分片维护的可用副本列表)。
  4. 一旦所有副本列表都成功执行了操作并响应了主副本,主副本就会向客户端确认请求已成功完成。

故障处理

ISR 中的副本没有同步完成,或者相应超时,primary ** 向 master 发送从 ISR 移除问题shard** 的请求, master 确认后 primary 才确认写完成,master 指导其他 node 开始构建 shard copy(副本分片)以恢复集群的健康。

基本读取模型

Elasticsearch 中的读取可以是非常轻量级的 ID 查找,也可以是具有复杂聚合的繁重搜索请求,需要占用大量 CPU 资源。主备份模型的优点之一是它使所有分片副本保持相同(运行中操作除外)。因此,单个同步副本足以满足读取请求。

  1. node 收到读取请求时,该 node 负责将其转发到持有相关 shard 的 node,整理响应并响应客户端。我们称该节点为该请求的协调节点coordinating node
  2. 其他 node 收到协调节点 shard 的读取请求。
  3. 分片复制组中轮询round robin)primary + replica shard,将分片级别的读取请求发送到选定的副本(copies)。
  4. 结合结果并做出回应。注意,在通过 ID 查找的情况下,只有一个分片是相关的,这一步可以跳过。

2.Index API

1.简单的例子

# 没有 index 默认会自动创建
PUT twitter/_doc/1
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

response

{
  "_index" : "twitter",  	// 索引名称
  "_type" : "_doc",			// 默认的 type 
  "_id" : "1",				// 自动生成的文档 id
  "_version" : 1,			// 文档版本
  "result" : "created",		// 执行结果
  "_shards" : {				// 分片复制的结果
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

2.自动创建索引的设置

# 部分自动创建索引
PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "twitter,index10,-index1*,+ind*" 
    }
}

# 禁止自动创建索引
PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "false" 
    }
}

# 默认所有名称都可以自动创建
PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "true" 
    }
}

3.禁用自动生成 id

# 已经有 id = 1 的 document 就报错
PUT twitter/_doc/1?op_type=create
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

# 或者这样,存在 id = 1 的 document 也报错
PUT twitter/_doc/1/_create
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

# 这样会自动生成 id,注意,POST 代表更新,PUT 代表 create
POST twitter/_doc/
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

4.乐观锁

乐观锁:认为当前线程修改共享数据时认为其他线程不会来修改共享数据,否则就报错。

优点:并发能力高,因为不给数据加锁。

缺点:修改的时候客户端要提供版本号,版本号不同需要重修修改,多次反复。

# 用 if_seq_no 和 if_primary_term 控制并发,也可以用 version
PUT products/_doc/1567?if_seq_no=362&if_primary_term=2
{
    "product" : "r2d2",
    "details" : "A resourceful astromech droid",
    "tags": ["droid"]
}

3.GET API

1.get api 是 Realtime 的,get 时会执行 refresh。不执行 refresh 操作可以设置 `realtime=false

2.常用操作

# gep api 获取文档,默认的 type 得写
GET twitter/_doc/0

# HEAD 判断是否存在,存在返回"200 - OK" ,不存在返回"404 - Not Found"
HEAD twitter/_doc/0

# _source_includes 可以传数组,指定哪些字段包含 _source, _source_excludes 表示排除
GET twitter/_doc/0?_source_includes=*.id&_source_excludes=entities

# `_source=false` 可以过滤掉 `_source`
GET twitter/_doc/0?_source=false

# 只获取 _source 字段
GET twitter/_doc/1/_source

# _source 选择或者排除某些字段
GET twitter/_doc/1/_source?_source_includes=*.id&_source_excludes=entities

# _source 有一个 HEAD 变体,可以测试文档 _source 是否存在。如果在 settings 中被禁用,文档将没有 _source。
HEAD twitter/_doc/1/_source

response

{
  "_index" : "products",
  "_type" : "_doc",
  "_id" : "1567",
  "_version" : 9,
  "_seq_no" : 8,
  "_primary_term" : 1,
  "found" : true,	// 是否存在
  "_source" : {
    "product" : "r2d2",
    "details" : "A resourceful astromech droid",
    "tags" : [
      "droid"
    ]
  }
}

3.store 设置不单独存储,默认是 true

# 创建 index 设置 mappings
PUT twitter
{
   "mappings": {
      "_doc": {
         "properties": {
            "counter": {
               "type": "integer",
               "store": false
            },
            "tags": {
               "type": "keyword",
               "store": true
            }
         }
      }
   }
}

# 新建字段
PUT twitter/_doc/1
{
    "counter" : 1,
    "tags" : ["red","blue"]
}

# GET API 获取不到 
GET twitter/_doc/1?stored_fields=tags,counter

# store 不影响_source 的内容
GET twitter/_doc/1

response

# GET twitter/_doc/1?stored_fields=tags,counter
{
  "_index" : "twitter",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "fields" : {
    "tags" : [
      "red",
      "blue"
    ]
  }
}

# GET twitter/_doc/1
{
  "_index" : "twitter",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "counter" : 1,
    "tags" : [
      "red",
      "blue"
    ]
  }
}

4.Delete API

1.简单的例子

DELETE /twitter/_doc/1

2.允许指定 if_seq_noif_primary_term参数

3.可以指定 version ,确保没有其他线程修改

4.可以设置 timeout=5m ,5分钟超时时间,默认1分钟

5.删除时会自动 refresh。

6.Delete by Query Api

POST twitter/_delete_by_query
{
  "query": { 
    "match": {
      "message": "some message"
    }
  }
}

5.UPDATE API

1.简单的例子

PUT test/_doc/1
{
    "counter" : 1,
    "tags" : ["red"]
}

2.脚本更新,计数器加 参数的值

POST test/_doc/1/_update
{
    "script" : {
        "source": "ctx._source.counter += params.count",
        "lang": "painless",
        "params" : {
            "count" : 4
        }
    }
}

3.可以在列表中添加一个元素(如果标签存在,它仍然会被添加,因为这是一个列表,不去重)

POST test/_doc/1/_update
{
    "script" : {
        "source": "ctx._source.tags.add(params.tag)",
        "lang": "painless",
        "params" : {
            "tag" : "blue"
        }
    }
}

4.列表中移除第一个元素

POST test/_doc/1/_update
{
    "script" : {
        "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
        "lang": "painless",
        "params" : {
            "tag" : "blue"
        }
    }
}

5.向文档添加一个新字段 new_field

POST test/_doc/1/_update
{
    "script" : "ctx._source.new_field = 'value_of_new_field'"
}

6.从文档中删除一个字段,

POST test/_doc/1/_update
{
    "script" : "ctx._source.remove('new_field')"
}

7.如果tags字段包含green,则此示例将删除文档,否则它什么都不做 ( noop)

POST test/_doc/1/_update
{
    "script" : {
        "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
        "lang": "painless",
        "params" : {
            "tag" : "green"
        }
    }
}

8.部分文档更新,要全部替换请使用 index API

POST test/_doc/1/_update
{
    "doc" : {
        "name" : "new_name"
    }
}

9.文档尚不存在,则upsert元素的内容将作为新文档插入。如果文档确实存在,那么 script将改为执行:

POST test/_doc/1/_update
{
    "script" : {
        "source": "ctx._source.counter += params.count",
        "lang": "painless",
        "params" : {
            "count" : 4
        }
    },
    "upsert" : {
        "counter" : 1
    }
}

10.如果您希望您的脚本无论文档是否存在都运行,设置 scripted_upserttrue

POST sessions/session/dh3sgudg8gsrgl/_update
{
    "scripted_upsert":true,
    "script" : {
        "id": "my_web_session_summariser",
        "params" : {
            "pageViewEvent" : {
                "url":"foo.com/bar",
                "response":404,
                "time":"2014-01-01 12:32"
            }
        }
    },
    "upsert" : {}
}

11.doc_as_upserttrue将使用的内容doc作为upsert值,而不是发送部分doc加上一个upsert`文档

POST test/_doc/1/_update
{
    "doc" : {
        "name" : "new_name"
    },
    "doc_as_upsert" : true
}

更新操作支持以下查询字符串参数:

参数 解释
retry_on_conflict 在更新的获取和索引阶段之间,另一个进程可能已经更新了同一个文档。默认情况下,更新将因版本冲突异常而失败。该retry_on_conflict 参数控制在最终抛出异常之前重试更新的次数。
routing 路由用于将更新请求路由到正确的分片,并在更新的文档不存在时为 upsert 请求设置路由。不能用于更新现有文档的路由。
timeout 等待分片可用的超时时间。
wait_for_active_shards 在继续更新操作之前需要处于活动状态的分片副本数。有关详细信息,请参见此处
refresh 控制此请求所做的更改何时对搜索可见。请参阅 刷新
_source 允许控制是否以及如何在响应中返回更新的 _source。默认情况下不返回更新的源。
version 更新 API 在内部使用 Elasticsearch 版本控制支持,以确保文档在更新期间不会更改。您可以使用该version 参数指定仅当文档版本与指定版本匹配时才应更新文档。

更新 API 不支持外部(版本类型externalexternal_gte)或强制(版本类型force)版本控制

支持if_seq_noif_primary_term,错误返回 VersionConflictException 409 状态码

6.BULK API

支持的操作有indexcreatedelete,和update

indexcreate 下一行是 _source,有相同的 id 则失败。

delete 下一行没有 _source。

update期望在下一行指定部分文档、更新插入和脚本及其选项。

如果您向 提供文本文件输入curl,则必须使用 --data-binary标志而不是普通-d

POST _bulk
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
$ cat requests
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
$ curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary "@requests"; echo
{"took":7, "errors": false, "items":[{"index":{"_index":"test","_type":"_doc","_id":"1","_version":1,"result":"created","forced_refresh":false}}]}

7.Search API

1.简单的例子

DELETE twitter
POST /twitter/_doc
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

GET /twitter/_search?q=user:kimchy
参数 解释
q 查询字符串(映射到query_string查询,有关详细信息,请参阅 查询字符串查询)。
df 在查询中未定义字段前缀时使用的默认字段。
analyzer 分析查询字符串时要使用的分析器名称。
analyze_wildcard 是否应分析通配符和前缀查询。默认为false.
batched_reduce_size 协调节点上应立即减少的分片结果数。如果请求中的潜在分片数量可能很大,则应将此值用作保护机制以减少每个搜索请求的内存开销。
default_operator 要使用的默认运算符可以是ANDOR。默认为OR.
lenient 如果设置为 true 将导致基于格式的失败(如向数字字段提供文本)被忽略。默认为假。
explain 对于每个命中,包含对如何计算命中得分的解释。
_source 设置为false禁用_source字段的检索。您还可以使用_source_includes&检索部分文档_source_excludes( 有关更多详细信息,请参阅请求正文文档)
stored_fields 为每次命中返回的文档的选择性存储字段,以逗号分隔。不指定任何值将导致没有字段返回。
sort 排序执行。可以是fieldName, 或 fieldName:asc/的形式fieldName:desc。fieldName 可以是文档中的实际字段,也可以是_score表示基于分数排序的特殊名称。可以有多个sort参数(顺序很重要)。
track_scores 排序时,设置为true以仍然跟踪分数并将它们作为每次命中的一部分返回。
track_total_hits 设置为false以禁用对匹配查询的总命中数的跟踪。(有关更多详细信息,请参阅索引排序)。默认为真。
timeout 搜索超时,限制搜索请求在指定的时间值内执行,并在过期时保释累积到该点的命中。默认为无超时。
terminate_after 为每个分片收集的最大文档数,达到该数量时查询执行将提前终止。如果设置,响应将有一个布尔字段terminated_early来指示查询执行是否实际上已终止_早期。默认为 no terminate_after。
from 要返回的命中索引的起始位置。默认为0.
size 要返回的点击次数。默认为10.

2.Query DSL

GET /_search
{
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

3.from size

GET /_search
{
    "from" : 0, "size" : 10,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

4.sort

# sort
PUT /my_index
{
    "mappings": {
        "_doc": {
            "properties": {
                "post_date": { "type": "date" },
                "user": {
                    "type": "keyword"
                },
                "name": {
                    "type": "keyword"
                },
                "age": { "type": "integer" }
            }
        }
    }
}

GET /my_index/_search
{
    "sort" : [
        { "post_date" : {"order" : "asc"}},
        "user",
        { "name" : "desc" },
        { "age" : "desc" },
        "_score"
    ],
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

# mode 使用
PUT /my_index/_doc/1?refresh
{
   "product": "chocolate",
   "price": [20, 4]
}

POST /my_index/_search
{
   "query" : {
      "term" : { "product" : "chocolate" }
   },
   "sort" : [
      {"price" : {"order" : "asc", "mode" : "avg"}}
   ]
}

3.Mapping

mapping 是定义文档中的字段是否存储、是否索引,和字段的数据类型

1.一个简单的例子

PUT my_index 
{
  "mappings": {
    "_doc": { 
      "properties": { 
        "title":    { "type": "text"  }, 
        "name":     { "type": "text"  }, 
        "age":      { "type": "integer" },  
        "created":  {
          "type":   "date", 
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    }
  }
}

2.string 包含 keyword 和 text 两种类型。

3.keyword用于排序,和聚合,只能按其确切值进行搜索不能设置分词。

4.date 类型可以是日期类型的字符串,long 类型的毫秒数,或者秒数。date 类型有一个 format 代表格式,自定义可以为 “yyyy-MM-dd”,内部类型有 datedate_hour_minute_second等已定义类型。

PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "date1": {
          "type": "date",
          "format": "yyyy-MM-dd",
          "doc_values": false
        },
        "date2":{
          "type": "date",
          "format": "year_month"
        },
        "date3":{
          "type": "date",
          "format": "year_month_day"
        },
        "date4":{
          "type": "date",
          "format": "epoch_second"
        },
        "date5":{
          "type": "date",
          "format": "epoch_millis"
        },
        "date6":{
          "type": "date",
          "format": "date_hour_minute_second"
        }
      }
    }
  }
}

5.analyzer 分析器

6.fields 用于不同的方式索引相同的字段

# 删除索引
DELETE my_index

# 创建索引时,设置一个分析器
# fields 用于两种分析器
PUT /my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "text": { 
          "type": "text",
          "fields": {
            "english": { 
              "type":     "text",
              "analyzer": "english"
            }
          }
        }
      }
    }
  }
}

# 用默认分析器分析, [The、quick、Brown、Foxes]
GET my_index/_analyze 
{
  "field": "text",
  "text": "The quick Brown Foxes."
}

# 用 english 分析器分析, [quick、Brown、Foxes]
GET my_index/_analyze 
{
  "field": "text.english",
  "text": "The quick Brown Foxes."
}

7.fielddata

排序、聚合和访问字段值,第一次访问时从磁盘读取 doc_value 到内存。

搜索需要解决*“哪些文档包含这个词?”的问题。,而排序聚合需要解决的问题是“这个字段对于这个文档的值是多少?”* .

fielddata 默认不能用于 text,Fielddata 会消耗大量堆空间,所以 text 不支持排序、聚合或访问

8.doc_value

doc_value 是磁盘上的数据结构,在文档索引时构建,和_source 的所用不同,分析后的text不支持doc_value,禁用可以节省磁盘空间

doc_value 是一种列式存储结构,高度优化了具有相同类型的数据的存储结构。

默认情况下,所有支持 doc_value 的字段都启用了。

4.Query DSL

一个例子

GET /_search
{
  "query": { 
    "bool": { 
      "must": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [ 
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}

Match All query

是最简单的查询,匹配所有。

GET /_search
{
    "query": {
        "match_all": {}
    }
}

Match Query(全文搜索)

Match Query 分词查询,支持类型text/numerics/date

1.match query 是一个 Boolean 类型的查询,对提供的内容分析,返回匹配到的

GET my_index/_search
{
    "query": {
        "match" : {
            "message" : {
                "query" : "this is a test",
                "operator" : "and"
            }
        }
    }
}

2.fuzziness模糊查询

GET /_search
{
    "query": {
        "match" : {
            "message" : {
                "query" : "this is a testt",
                "fuzziness": "AUTO"
            }
        }
    }
}

Term Query

1.精确的术语匹配

DELETE my_index
# 创建索引,full_text字段属于类型text,将被分词,exact_value 不被分词
PUT my_index
{
  "mappings": {
    "_doc": {
      "properties": {
        "full_text": {
          "type":  "text" 
        },
        "exact_value": {
          "type":  "keyword" 
        }
      }
    }
  }
}

# 插入数据 
PUT my_index/_doc/1
{
  "full_text":   "Quick Foxes!",  
  "exact_value": "Quick Foxes!"  
}

# term query,exact_value字段包含确切的 "Quick Foxes!"
GET my_index/_search
{
  "query": {
    "term": {
      "exact_value": "Quick Foxes!" 
    }
  }
}

# full_text 只包含 "Quick","Foxes",没有匹配到结果
GET my_index/_search
{
  "query": {
    "term": {
      "full_text": "Quick Foxes!" 
    }
  }
}

# 有查询结果,full_text 被分词,包含"foxes"
GET my_index/_search
{
  "query": {
    "term": {
      "full_text": "foxes" 
    }
  }
}

# match query 查询的时候被分词,可以匹配到结果
GET my_index/_search
{
  "query": {
    "match": {
      "full_text": "Quick Foxes!" 
    }
  }
}

2.wildcard 通配符查询

GET my_index/_search
{
    "query": {
        "wildcard": {
            "exact_value": {
                "value": "Qu*",
                "boost": 1.0,
                "rewrite": "constant_score"
            }
        }
    }
}

3.tearms query

GET /_search
{
    "query": {
        "terms" : { "exact_value" : ["Quick Foxes!", "elasticsearch"]}
    }
}

4.Ids query

GET /_search
{
    "query": {
        "ids" : {
            "type" : "_doc",
            "values" : ["1", "4", "100"]
        }
    }
}

5.regexp query 正则查询

GET /_search
{
    "query": {
        "regexp":{
            "name.first": "s.*y"
        }
    }
}

6.存在查询

GET /_search
{
    "query": {
        "exists": {
            "field": "user"
        }
    }
}

Multi Match Query

基于 match 的多字段匹配

GET /_search
{
  "query": {
    "multi_match" : {
      "query":    "this is a test", 
      "fields": [ "subject", "message" ] 
    }
  }
}

5.analysis(分析)

1.分析是将 text 转换为倒排索引用于搜索,分析由分析器 analyzer执行,

2.分析器是默认使用的是standard-analyzer,会经过 分词、转小写、删除停用词等步骤。

# 查看分析器分析后的结果
POST _analyze
{
  "analyzer": "standard",
  "text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}

分析结果

[ the, 2, quick, brown, foxes, jumped, over, the, lazy, dog's, bone ]

3.索引和查询可能使用的是不同的分析器

6.Dynamic Mapping

新字段的自动检测和添加称为 动态映射

配置动态 mapping 的规则称为 动态模板

1.document 中没有出现的字段会自动添加到 mapping 中

2.dynamic设置为 false忽略新字段,设置为strict遇到未知字段时抛出异常,默认是true:

JSON 数据类型 Elasticsearch 数据类型
null 未添加任何字段。
true 或者 false boolean
float float
integer lone
object object
array 取决于第一个非null值。
string date、double、long、text、keyword

3.date 类型

自动检测的日期类型为:[ "strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]

date_detection 禁用 date 检测。

dynamic_date_formats 为自定义的日期检测类型。

PUT my_index
{
  "mappings": {
    "_doc": {
      "date_detection": false
    }
  }
}

# 被识别为 text 类型
PUT my_index/_doc/1 
{
  "create": "2015/09/02"
}

4.数值类型

numeric_detection 启用数值检测

PUT my_index
{
  "mappings": {
    "_doc": {
      "numeric_detection": true
    }
  }
}

# 被检测为 float 和 lone 类型
PUT my_index/_doc/1
{
  "my_float":   "1.0", 
  "my_integer": "1" 
}

7.Dynamic templates

my_template_name:模板的名字

match conditions:包含 match_mapping_type, match, match_pattern, unmatch, path_match, path_unmatch.

mapping:目标 mapping

  "dynamic_templates": [
    {
      "my_template_name": { 
        ...  match conditions ... 
        "mapping": { ... } 
      }
    },
    ...
  ]

例子:

# 指定动态模板,integers 是名字,match_mapping_type 是匹配条件,
PUT my_index
{
  "mappings": {
    "_doc": {
      "dynamic_templates": [
        {
          "integers": {
            "match_mapping_type": "long",
            "mapping": {
              "type": "integer"
            }
          }
        },
        {
          "strings": {
            "match_mapping_type": "string",
            "mapping": {
              "type": "text",
              "fields": {
                "raw": {
                  "type":  "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        }
      ]
    }
  }
}

PUT my_index/_doc/1
{
  "my_integer": 5, 
  "my_string": "Some string" 
}

match 和 unmatcg

匹配字段以long 开头,不匹配 _text 结束的字段

PUT my_index
{
  "mappings": {
    "_doc": {
      "dynamic_templates": [
        {
          "longs_as_strings": {
            "match_mapping_type": "string",
            "match":   "long_*",
            "unmatch": "*_text",
            "mapping": {
              "type": "long"
            }
          }
        }
      ]
    }
  }
}

PUT my_index/_doc/1
{
  "long_num": "5", 
  "long_text": "foo" 
}

match_pattern 正则匹配

  "match_pattern": "regex",
  "match": "^profit_\d+$"

path_match and path_unmatch

PUT my_index
{
  "mappings": {
    "_doc": {
      "dynamic_templates": [
        {
          "full_name": {
            "path_match":   "name.*",
            "path_unmatch": "*.middle",
            "mapping": {
              "type":       "text",
              "copy_to":    "full_name"
            }
          }
        }
      ]
    }
  }
}

PUT my_index/_doc/1
{
  "name": {
    "first":  "John",
    "middle": "Winston",
    "last":   "Lennon"
  }
}

{name} and {dynamic_type}

PUT my_index
{
  "mappings": {
    "_doc": {
      "dynamic_templates": [
        {
          "named_analyzers": {
            "match_mapping_type": "string",
            "match": "*",
            "mapping": {
              "type": "text",
              "analyzer": "{name}"
            }
          }
        },
        {
          "no_doc_values": {
            "match_mapping_type":"*",
            "mapping": {
              "type": "{dynamic_type}",
              "doc_values": false
            }
          }
        }
      ]
    }
  }
}

PUT my_index/_doc/1
{
  "english": "Some English text", 
  "count":   5 
}

8.refresh

9.Flush

10.原理篇

1.一个ElasticSearch的Shard本质上是一个Lucene Index。

2.在Lucene里面有很多小的segment。

3.Segment 内部有 Inverted Index、Stored Fields、Document Values、Cache

倒排索引

Inverted Index主要包括两部分:

  • 一个有序的数据字典 Dictionary(包括单词Term和它出现的频率),这部分数据存储的格式是 B+tree

  • 与单词Term对应的Postings(即存在这个单词的 document)

Stored Field

第一次读取 doc values 的时候会把缓存到内存,text 类型默认不加载到内存,需要手动设置(不推荐);

用来排序、聚合、搜索。

Document Values

把数据索引到 es 的时候会创建 doc_value=true 的字段到磁盘;

用来排序、聚合、搜索。

上一篇:开发环境


下一篇:使用Git时如何将不需要提交的文件加入忽略列表