前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、读写文档

Elasticsearch 中的每个索引都分为多个分片,每个分片可以有 多个副本,这些副本称为复制组

注意:在添加或删除文档时必须保持同 步。如果不这样做,将导致从一个副本中读取的数据与从另一个副本 中读取的数据表现出截然不同的结果。保持主分片和副本间

复制模型:两两副 本间的数据同步并提供读取服务的过程,我们称之为数据复制模型。

下图展示了复制组的具体含义,此复制组有三个分片,加粗的是主分片,其他两个是副本,这三个分片的数据必须保持一致

image-20220601174517312

1.1、主备模型

Elasticsearch 的数据复制模型是基于主备 ( primary - backup ) 模型的,这个模型在微软研究中心的 Pacifica 论文中有很好的描述。 该模型基于复制组中作为主分片的单个数据分片。意思是,假设一个 索引有3个分片、2个副本,那么每个子索引共有3个分片,其中一个 是主分片,两个是副本,

为了便于描述主分片,我们称主分片为 primary,称副本为 replicaprimary 用作所有索引操作的主入口点,它负责验证它们并确保它们是正确的。一旦索引操作被primary 接受,primary 还负责将该操作复制到其他replica(分发请求到其他 replica)。另外约定,集群中有若干个节点,其中只有一个是活跃的 主节点,它负载管理集群,我们把它称为master。

1.2、基本写模型

Elasticsearch 中的每个索引操作首先使用路由 (通常基于文档 ID )解析到一个复制组。一旦确定了复制组,该操作将在内部转发到 该组的当前 primary

primary 负责验证操作并将其转发到其他 replica。由于 replica 可以离线,因此不需要 primary复制到所有 replica

⬤ 相反,Elasticsearch 维护一个应该完成接收操作的 replica 列表,此列表称为同步副本组,由主节点维护。顾名思义,这些是一 组“好”的分片拷贝,保证已经处理了所有的索引和删除操作,这些 操作已经被用户确认。primary 负责维护这个不变量,因此必须将所 有操作复制到这个同步副本组中的每个 replica

1.3.1、primary 写流程

1、验证传入操作,如果结构无效则拒绝该操作。例如,向一个数 字字段传输一个对象类型。

2、在本地执行操作,即索引或删除相关文档。这还将验证字段的内容,并在需要时拒绝。例如,关键字值对于 Lucene中的索引而言太长了。

3、将操作转发到当前同步副本组中的每个 replica,如果有多个 replica,这是并行完成的。

4、一旦所有 replica 都成功地执行了操作并对 primary 作出了响 应,primary 就确认完成了请求并返回给用户。

1.3.2、写流程错误处理

索引数据期间可能会有多种异常情况发生,磁盘可能损坏,节点可能彼此断开,或者某些配置错误可能导致操作在 replica 失败,尽管 在 primary 上成功。这种情况虽然不常见,但 primary 必须对它们作 出反应。

1、故障转移:如果 primary 本身发生故障,primary 所在的节点将向 master 节点发送相关的消息。索引操作将等待(默认情况下最多1分钟) master 将其中一个 replica 提升为新的 primary。然后该操作将被转发 到新的 primary 进行处理。同时,master 还监视节点的运行状况,并可能决定主动降级 primaryreplica,当包含 primary 的节点由于网络问题与集群隔离时,通常会发生这种情况。

2、副本摘除:一旦在 primary上成功执行了操作,primary 就必须处理在 ` replica上执行时潜在的故障。这可能是由于 replica上的实际故障或 网络问题导致操作无法到达 replica (或阻止replica响应)。所有这 些问题会造成相同的最终结果: 作为同步副本组的一部分的 replica会 错过即将被确认的操作。为了避免违反不变量,primarymaster 发 送一条消息,请求从同步副本组中删除有问题的replica。只有在 master 确认清除 replica 后,primary 才会确认该操作。同时, master` 还将指示另一个节点开始构建新的副本,以便将系统恢复到健 康状态。

3、主节点下线: 在将操作转发到其他 replica 时,primary 将使用 replica 来验证它是否仍然是活动的 primary。如果由于网络分区(或GC时间过长)而 隔离了primary,则在知道到它已降级之前,它可能会继续处理传入的索引操作。来自过时 primary 的操作将被 replica拒绝,当 primary 接收到来自拒绝其请求的 replica的响应时,它将到达 master并知道 它已经被替换,然后将操作路由到新的 primary

1.3、基本读模型

Elasticsearch 中的读取可以是非常轻量的按 ID 查找,也可以是 一个具有复杂聚合的繁重搜索请求,这些聚合需要非常大的 CPU 能 力。主备 (primary - backup )模型的一个优点是它保持所有的分片 (primaryreplica )是等同的。因此,单个同步拷贝(称之为相关分片组)就足以满足读取请求。

1.3.1、读流程

当节点接收到读取请求时,该节点负责将其转发到保存相关分片的节点整理响应,并向客户机返回结果。该节点被称为该请求的协调 节点。基本流程如下:

1、将读取请求解析到相关分片组。注意,由于大多数搜索将被发送到一个或多个索引,所以它们通常需要从多个分片中读取,每个分片表示数据的不同子集。

2、从同步副本组中选择一个相关 shard 的活动分片。这可以是 primary,也可以是 replica。默认情况下,Elasticsearch 只需在分 片之间循环搜索。

3、向所选分片发送读取请求。

4、将结果整合。请注意,在按 ID 查找的情况下,只有一个分片是 相关的,可以跳过此步骤。

1.3.2、读流程错误处理

当一个分片未能响应读取请求时,协调节点将请求发送到同步副 本组中的另一个分片。重复失败可能导致没有可用的分片。为了确保快速响应,如果一个或多个分片失败,以下 API 将以部分结果响应:

⬤ Search API

⬤ Multi Search

⬤ Bulk

⬤ Multi Get

包含部分结果的响应仍然提供200 OK HTTP状态代码。相关分 片的失败信息记录在响应头部字段里。

2、索引 API

索引操作成功执行时,successful 至少是 1

说明:默认情况下,当索引操作成功返回时,有可能一些replica 还没有开始或完成,因为只要 primary成功执行,就会返回,这种行 为可以调整。其实这样做的目的是快速响应,一般的场景并不需要等 待所有分片都完成索引操作再返回,除非对数据安全要求极高的场 景。

key 说明
_shards 头提供有关索引操作的复制过程的信息
total 指示索引操作应在多少个分片 (主 primaryreplica )上执行
successful 指示索引操作成功执行的分片数
failed 在副本分片上索引操作失败的情况下包含与复制相关的错误的数组。

入参:

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

出参:

{
    "_shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 2
    },
    "_index" : "twitter",
    "_type" : "_doc",
    "_id" : "1",
    "_version" : 1,
    "_seq_no" : 0,
    "_primary_term" : 1,
    "result" : "created"
}

2.1、自动创建索引

当索引文档时,如果索引不存在,会自动创建索引。索引操作还 将创建一个动态映射(如果尚未存在)。默认情况下,如果需要,新字段和对象将自动添加到映射定义中。

自动创建索引由 action.auto_create_index 设置控制。

1、此设置默 认为 true,这意味着索引总是自动创建的。

2、也可以设置只有匹配特定模式的索引才允许自动创建索引,方法是将此设置的值更改为这些匹配模式的逗号分隔列表。

3、还可以通过在列表中的模式前面加上 + 或 - , 明确地允许和禁止使用它。

4、最后,通过将此设置更改为 false,可以完 全禁用它。可以在 elasticsearch.yml 中配置,也可以通过如下URL 配置。下面是几个示例

2.1.1、特定模式才允许创建

只允许自动创建名为 twitterindex 10 的索引,不允许创建其他与 index1* 匹配的索引


PUT _cluster/settings
{
  "persistent": {
    "action.auto_create_index": "twitter,index10,-index1*,+ind*"  
  }

2.1.2、完全禁用索引的自动创建


PUT _cluster/settings
{
  "persistent": {
    "action.auto_create_index": "false" 
  }

2.1.3、允许使用任何名称自动创建索引

是默认设置

PUT _cluster/settings
{
  "persistent": {
    "action.auto_create_index": "true" 
  }

2.1.4、索引存在 ( 覆盖&失败 )

索引操作还接受一个 op_type 参数,它可以用来强制 create 操 作,允许 put-if-absent 的行为。使用create 时,如果索引中已存在具 有该 ID的文档,则索引操作将失败。

⬤ 默认情况下,当文 档存在时直接覆盖。

⬤ 当索引文档时,如果带有 &op_type=true 参 数,明确指明是创建文档,如果文档存在就报错。

入参:

PUT twitter/_doc/1?op_type=create
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

出参:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "version_conflict_engine_exception",
        "reason" : "[1]: version conflict, document already exists (current version [1])",
        "index_uuid" : "d9PDPxM-Tja9Hb1k1jsEbA",
        "shard" : "0",
        "index" : "twitter"
      }
    ],
    "type" : "version_conflict_engine_exception",
    "reason" : "[1]: version conflict, document already exists (current version [1])",
    "index_uuid" : "d9PDPxM-Tja9Hb1k1jsEbA",
    "shard" : "0",
    "index" : "twitter"
  },
  "status" : 409
}

2.2、ID 自动生成

索引操作可以在不指定 ID 的情况下执行。在这种情况下,将自动 生成一个 ID。此外,op_type将自动设置为create。下面是一个例子 (注意使用 POST 而不是 PUT )

2.3、路由

默认情况下,碎片放置(或路由)是通过使用文档 id 值的散列来控制的。为了实现更明确的控制,可以使用路由参数直接在每个操作的基础上指定路由器使用的散列函数的值。

注意:在设置显式 mapping 时,可以选择使用 routing 字段从文档本身 提取路由值。如果定义了 mapping_routing 值并将其设置为必需, 则如果没有提供可提取路由值,索引操作将失败。

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

2.4、分发

索引操作根据路由定向到 primary ,并在包含此分片的实际节点 上执行。在 primary 完成操作后,如果需要,操作将分发到需要的其他分片。

2.5、等待活动分片

为了兼顾系统写入的效率和可靠性,可以将索引操作配置为在继 续操作之前等待一定数量的活动分片。如果所需数量的活动分片不可用,则写入操作必须等待并重试,直到所需分片已启动或发生超时。 默认情况下,写入操作仅在继续之前等待 primary 完成 (即 wait_for_active_shards = 1 ) 。

1、可以通过设置 index.write.wait_for_active_shards 来 动 态 重 写 此 默 认 值 。

2、要 更 改 每个请求操作的此行为,可以使用 wait_for_active_shards 请求参 数。wait_for_active_shards 的有效值是任何正整数,最多为分片总 数。指定负值或大于分片数的数字将引发错误。

例如:假设有一个由 3 个节点 ( ABC ) 组成的集群,并且创 建了一个索引 index ,其中副本数设置为 3 (结果是共 4 个分片(但是实际上不存在4个分配))。 如果我们尝试索引操作

1、默认情况下,该操作将仅确保 primary 在继续操作之前可用。这意味着,即使 BC 发生故障,并且 A 托管了 primary , 索 引 操 作 仍 然 继 续 进 行 。

2、如果在请求中将 wait_for_active_shards 设置为 3 ( 并且所有 3 个节点都已启动),那么索引操作将需要3个活动的 shard 副本才能继续。这一要求应该满足,因为集群中有 3 个活动的节点,每个节点都保存一个 shard 副本。 但是,如果我们将 wait_for_active_shards 设置为 all ( 或设置为 41, 这是相同的),则索引操作将不会继续,因为索引中没有每个 shard 的所有4个副本。除非在集群中出现新节点以承载分片的第四副本, 否则操作将超时

2.6、detect_noop 参数

使用索引 API 更新文档时,即使文档没有更改,也会始终创建文档的新版本。如果不想这样做,可以使用detect_noop = true 参数。这 个参数的作用是在更新之前与原文档对比,如果没有字段值的变化, 则不做更新操作。

3、GET API

3.1、根据id 查询索引文档

GET API 允许根据其 ID 从索引中获取 JSON 文档。以下示例从 twitter 的索引中获取 ID 值为 1JSON文档:

入参:

GET twitter/_doc/1

出参:

{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
  }
}

3.2、head 检查文档是否存在

3.2.1、不存在

入参:

HEAD twitter/_doc/0

出参:

{
    "statusCode": 404,
    "error": "Not Found",
    "message": "404 - Not Found"
}

3.2.2、存在

入参:

HEAD twitter/_doc/1

出参:

200 - OK

3.3、实时性

默认情况下,GET API 是实时的,不受索引刷新频率的影响。如果文档已更新但尚未刷新,则 GET API 将在适当时机发出刷新调用, 以使文档可见。这还将使上次刷新后更改的其他文档可见。如果需要禁用此特性,可以将 realtime 参数设置为 false

3.4、字段选择

3.4.1、_source_includes_source_excludes

如果只需要完整 _source 中的一个或两个字段,可以使用 _source_includes_source_excludes 参数来包含或排除字段。这 对于大型文档尤其有用,因为部分字段检索可以节省网络开销。两个参数都采用逗号分隔的字段列表或通配符表达式。

入参:

GET twitter/_doc/1?_source_includes=*.date&_source_excludes=entities

3.4.2、_source

如果只需指定 include ,可以使用较短的表示法:

入参:

GET twitter/_doc/1?_source=*.id,retweeted

3.5、直接获取_source

可以使用/{index}/_source/{id} 仅获取文档的 `source 字段,而不 返回任何其他内容,用法如下:

3.5.1、只返回 _source

入参:

GET twitter/_source/1

出参:

{
  "counter" : 1,
  "tags" : [
    "red"
  ]
}

3.5.2、筛选 _source 字段

入参:

GET twitter/_source/1/?_source_includes=*&_source_excludes=entities

出参:

{
  "counter" : 1,
  "tags" : [
    "red"
  ]
}

3.5.3、检查 _source 是否存在

入参:

HEAD twitter/_source/1

出参:

200 - OK

3.6、routing 路由

如果在索引文档时使用了路由参数,搜索时也应该加上该参数。 当然搜索时不加也是可以的,这会降低性能。如下示例,指定了路 由:

GET twitter/_doc/2?routing=user1

3.7、preference 参数

preference 参数的作用是控制优先从哪个 shard 获取数据。默认 情况下是随机选择的。一般情况下可以设置为_local,这可以降低网 络开销。

local :如果可能,该操作将更倾向于在本地分配的分片上执行。

Custom (string) value: 自定义值将用于保证相同的分片将用于相同的自定义值。 当在不同的刷新状态下击中不同的分片时,这有助于“跳跃值”。 示例值可以是 Web 会话 ID 或用户名之类的东西。

3.8、refresh 参数

可以将 refresh 参数设置为 true,以便在GET 操作之前刷新相关 的分片并使其可见。将其设置为 true 应慎重考虑,因为这可能导致系 统负载过重,并减慢索引速度。

3.9、分发

GET 操作被散列到一个特定的分片 ID上,然后被重定向到该分片 ID对应的一个副本,并返回结果。副本是主分片及其在该分片 ID上的 副本。这意味着拥有的副本越多,将拥有更好的扩展能力

1.10、存储字段

GET 操作允许指定一组存储字段 ( store 属性值为 true ),这些 字段将通过传递 stored_fields 参数返回。如果未存储请求的字段,则 将忽略它们。例如,首先建立以下映射

入参:

PUT twitter
{
   "mappings": {
       "properties": {
          "counter": {
             "type": "integer",
             "store": false
          },
          "tags": {
             "type": "keyword",
             "store": true
          }
       }
   }
}

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

1.10.1、检索数据

入参:

GET twitter/_doc/1?stored_fields=tags,counter

出参:

{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "fields" : {
    "tags" : [
      "red"
    ]
  }
}

4、删除 API

4.1、根据特定文档 Id 删除

删除 API ( DELETE ) 允许根据特定文档的 ID 从其中删除 JSON 文档。下面的示例将 ID为1的JSON文档从twitter 索引中删除:

入参:

DELETE /twitter/_doc/1

出参:

{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 2,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

4.2、查询删除

4.2.1、查询匹配并删除

查询删除 API ( _delete_by_query )是对每个与查询匹配的文档 执行删除操作。

删除过程:_delete_by_query 操作在启动时会获取索引的一个快照,并使用 内部版本控制删除找到的内容。这意味着,如果文档在获取快照的时 间和处理删除请求的时间之间发生更改,则会出现版本冲突。当版本匹配时,文档将被删除

具体过程:

1、在_delete_by_query 执行期间,将按顺序执行多个搜索请求,以查找所有要删除的匹配文档。每当找到一批文档时,都会执行相应的 批量请求来删除所有这些文档。

2、如果搜索或批量请求被拒绝, _delete_by_query 按照默认策略重试被拒绝的请求(最多10次,指数 下降)。达到最大重试次数限制会导致 _delete_by_query 中止,并在响应的failures中返回所有失败信息。

3、已执行的删除操作仍然保持不 变。换句话说,操作不会回滚,只会中止。

4、当第一个失败导致中止时,由失败的批量请求返回的所有失败信息都会 在failures 元素中返 回,因此,可能会有相当多失败的实体。

4.2.1.1、简单的查询删除

入参:

POST twitter/_delete_by_query
{
  "query": { 
    "match": {
      "name": "HealerJean"
    }
  }
} 

出参:

{
  "took" : 34,
  "timed_out" : false,
  "total" : 1,
  "deleted" : 1,
  "batches" : 1,
  "version_conflicts" : 0,
  "noops" : 0,
  "retries" : {
    "bulk" : 0,
    "search" : 0
  },
  "throttled_millis" : 0,
  "requests_per_second" : -1.0,
  "throttled_until_millis" : 0,
  "failures" : [ ]
}

4.2.1.2、拒绝版本冲突中止

如果不想因版本冲突而让它们中止,那么在 URL 上设置 conflicts = proceed 或在请求正文中设置conflicts:proceed

举例:从 twitter 索引中删除 tweet

入参:

POST twitter/_delete_by_query?conflicts=proceed
{
 
  "query": {
    "match_all": {}
  }
}
 

4,2.1.3、一次删除多个索引文档

入参:

POST twitter,blog/_delete_by_query
 
{
  "query": {
    "match_all": {}
  }
}
 

4,2.1.4、routing 路由

如果提供了 routing ,则路由将复制到滚动( scroll ) 查询中,并 将操作限制在与该路由值匹配的分片上,如下示例:

入参:

POST twitter/_delete_by_query?routing=1
 
{
 
  "query": {
    "range" : {
        "age" : {
           "gte" : 10
        }
    }
  }
 
}

4,2.1.5、scroll_size 滚动批次

默认情况下,_delete_by_query 查询使用的滚动批次大小为 1000。可以使用scroll_size 参数更改批次大小

入参:

POST twitter/_delete_by_query?scroll_size=5000
 
{
    "query": {
        "term": {
            "user": "kimchy"
        }
    }
}

4.2.2、URL 参数

除了标准参数 ( 如 pretty ) 外,_delete_by_query API 还支持 refresh wait_for_completionwait_for_active_shardstimeoutscroll。

4.2.2.1、refresh

发送带有 refresh 参数的请求,将在请求完成后刷新涉及的所有分片。这与 DELETE APIrefresh 参数不同,后者只会刷新接收到删除请求的分片。同时,它不支持 wait_for 参数。

4.2.2.2、wait_for_completion

如 果 请 求 包 含 wait_for_completion = false 设 置 , 那 么 Elasticsearch 将执行一些预检查。启动请求,然后返回一个Task 以取消或获取任务的 状 态 。

Elasticsearch 还 将 在 .tasks/task/${taskId} 索引中创建此任务的记录文档,用户可以根 据需要保留或删除创建的文档,完成后删除它。这样 Elasticsearch 可以回收它使用的空间。

4.2.2.3、wait_for_active_shards & timeout

wait_for_active_shards 参数用来控制在继续执行请求之前必须激活多少个分片或副本。

timeout 参数用来控制每个写请求等待不可用分片变为可用的时间。

这两个参数在批量 API 中的工作方式完全相 同。由于 _delete_by_query 使用 scroll 搜索,还可以指定 scroll 参数 来控制“搜索上下文”保持活动的时间,例如 scroll = 10m 。默认为 5 分钟。

4.2.24、requests_per_second

requests_per_second 参数可以设置为任何正十进制数(1.4、 6、1000等),并通过用等待时间填充每个批来限制通过查询发出删 除操作批的速率。通过将 requests_per_second 设置为-1,可以禁用 限制

此限制是通过在批之间等待来完成的,这样就可以为 ` _delete_by_query 内部使用的滚动指定一个超时时间。这个时间是批 处理大小除以requests_per_second 与写入时间之差。默认情况下, 批处理大小为 1000 ,因此如果 requests_per_second 设置为 500` ,计算方式如下:

target_time = 1000/500 per second=2 seconds
wait_time = target_time - write_time = 2 seconds-.5seconds = 1.5 seconds

注意:由于该操作是作为单个 _bulk 请求发出的,因此较大的批大小将 导致 Elasticsearch 创建多个请求,并在启动下一个操作之前等待一 段时间,这是不平稳的。默认值为-1。

4.2.3、返回体

{
    "took": 147,
    "timed_out": false,
    "total": 119,
    "deleted": 119,
    "batches": 1,
    "version_conflicts": 0,
    "noops": 0,
    "retries": {
        "bulk": 0,
        "search": 0
    },
    "throttled_millis": 0,
    "requests_per_second": -1,
    "throttled_until_millis": 0,
    "failures": []
}
key 说明
took 整个操作从开始到结束的毫秒数。
timed_out 如果在执行_delete_by_query期间执行的任何 请求超时,则此标志为true
total 成功处理的文档数
deleted 成功删除的文档数
batches 分了多少批次执行
version_conflicts 版本冲突的文档数。
noops 对于_delete_by_query,此字段始终等于零。
retries 操作尝试的重试次数。
bulk 重试的批量操作数,
search 重试的搜索操作数。
throttled_millis 请求休眠以符合 requests_per_second 参数设置的毫秒数。
requests_per_second 每秒有效执行的请求数
throttled_until_millis _delete_by_query 响应中,此字段应始终等于零。它只有在使用 _tasks API 时才有意义,在 该 API 中,它指示下一次将再次执行请求的等待时间(从 epoch开始以毫秒为单位)。
failures ⬤ 如果请求处理中有任何不可恢复的错误,则记录 到这个失败数组中。如果不为空,那么请求会因为这些失败 而中止。
_delete_by_query是使用批处理实现的,任何失败 都会导致整个过程中止,但当前批处理中的所有失败都会收 集到此数组中。可以使用conflicts选项防止覆盖写入在版本 冲突时中止。

4.2.4、任务 API

可 以 使 用 任 务 API ( ` _tasks ` ) 获 取 任 何 正 在 运 行 的 _delete_by_query 的状态:

入参:

GET _tasks?detailed=true&actions=*/delete/byquery

解析:返回结果中的 status 字段,包含任务的实际状态。 total 字段 是重新索引预期执行的操作总数。可以通过updatedcreateddeleted 的字段的加总值来估计进度。当它们的总和等于合计字段时, 请求将完成。

出参:

{
    "nodes": {
        "r1A2WoRbTwKZ516z6NEs5A": {
            "name": "r1A2WoR",
            "transport_address": "127.0.0.1:9300",
            "host": "127.0.0.1",
            "ip": "127.0.0.1:9300",
            "attributes": {
                "testattr": "test",
                "portsfile": "true"
            },
            "tasks": {
                "r1A2WoRbTwKZ516z6NEs5A:36619": {
                    "node": "r1A2WoRbTwKZ516z6NEs5A",
                    "id": 36619,
                    "type": "transport",
                    "action": "indices:data/write/delete/byquery",
                    "status": {
                        "total": 6154,
                        "updated": 0,
                        "created": 0,
                        "deleted": 3500,
                        "batches": 36,
                        "version_conflicts": 0,
                        "noops": 0,
                        "retries": 0,
                        "throttled_millis": 0
                    },
                    "description": ""
                }
            }
        }
    }
}

4.2.4.1、使用任务ID,可以直接查找任务:

API 的优点是,它可以与 wait_for_completion = false 一起使 用,以透明地返回已完成任务的状态。

如果任务已完成,并且在其上设置了 wait_for_completion = false ,那么它将返回 resultserror 字 段。此功能的成本是创建的新的文档,需要手动来删除创建的文档。

入参:

GET /_tasks/r1A2WoRbTwKZ516z6NEs5A:36619

4.2.5、取消任务 API

可以使用取消任务 API ( _cancel ) 取消 _delete_by_query 进程:

可以使用任务 API 找到任务ID。取消应该很快发生,但可能需要几秒钟。上面的任务状态 API 将 继续列出相应的任务,直到该任务检查它是否已被取消并自行终止。

入参:

POST_tasks/r1A2WoRbTwKZ516z6NEs5A:36619/_cancel

4.2.6、动态调整 API

requests_per_second 的 值 可 以 在 运 行 时 使 用 动 态 调 整 API ( _rethrottle )进行更改:

1、可以使用任务API找到任务ID。就像在 _delete_by_query API上设置它一样, requests_per_second 可以置为-1以禁用限制,也可以是任何十进制数(如1.7或12)以限制到该级别。

2、加快查询速度的重新标记将立即 生效,但减慢查询速度的重新标记将在完成当前批处理后生效。这样可以防止滚动超时。

入参:

POST _delete_by_query/r1A2WoRbTwKZ516z6NEs5A:36619/_rethrottle?requests_per_second=-1

4.2.7、切片

_delete_by_query API 支持切片滚动,使删除过程并行。这种并行化可以提高效率,并提供一种方便的方法将请求分解为较小的部 分。

4.2.7.1、人工切片

通过为每个请求提供一个切片 ID 和切片总数,进行人工切片:

入参:

POST twitter/_update_by_query
{
  "slice": {
    "id": 0,
    "max": 2
  },
  "script": {
    "source": "ctx._source['extra'] = 'test'"
  }
}


POST twitter/_update_by_query
{
  "slice": {
    "id": 1,
    "max": 2
  },
  "script": {
    "source": "ctx._source['extra'] = 'test'"
  }
}

验证是否生效,入参:

GET _refresh
POST twitter/_search?size=0&q=extra:test&filter_path=hits.total

4.2.7.2、自动切片

可以让 _delete_by_query 过程自动并行化,方法是使用“切片滚 动”机制对 _id 进行切片

1、使用slices指 定要使用的切片数,把 slices 设置为 auto 将允许 Elasticsearch 选择要使用的切片数。 此设置将会为每个分片使用一个切片,直至达到某个限制。

2、如果存在多个源索引,它将根据具有最小分片数的索引选择切片数。通过在_delete_by_query API中添加 slices 会自动执行切片过 程。

入参:

POST twitter/_update_by_query?refresh&slices=5
{
  "script": {
    "source": "ctx._source['extra'] = 'test'"
  }
}

验证是否生效,入参:

POST twitter/_search?size=0&q=extra:test&filter_path=hits.total

4.2.7.3、切片数量选择

⬤ 如果使用自动切片机制,将为大多数索引选择一个合理的切片数字。

⬤ 如果要手动切片或调整自动切片,请遵循以下准则:

1、当切片数等于索引中的分片数时,查询性能最佳。如果该数字很大(例如500),请选择一个较小的数字,因为太多的切片会影响性能。设置高于分片数量的切片通常不会提高效 率并增加开销。

2、 删除性能随可用资源的切片数线性扩展。

3、查询或删除性能是否支配运行时间取决于重新索引的文档和 集群资源。

5、更新 API

5.1、使用 script 更新

5.2、部分字段更新

更新 API 还支持传递部分文档字段进行更新,在内部完成合并 (简单的递归合并、对象的内部合并、替换核心“键值”和数组)。 要完全替换现有文档,应使用索引 API。以下实例,通过部分更新机 制将现有文档添加新字段:

注意:如果同时指定了 docscript,则忽略 doc

入参:

POST /animal/_update/1?pretty
{
    "doc": {
        "name": "熊猫update"
    }
}

5.3、避免无效更新

⬤ 如果指定了 doc,则其值将与现有的 _source 合并。默认情况下, 不更改任何内容的更新并不会真正执行并返回 “result “: “noop

⬤ 因为传入的 name 值和 source中的一样,则忽略整个更新请求。 如果请求被忽略,响应中的 result元素将返回 noop

入参:

POST /animal/_update/1?pretty
{
    "doc": {
        "name": "熊猫update"
    }
}

出参:

{
  "_index" : "animal",
  "_id" : "1",
  "_version" : 17,
  "result" : "noop",
  "_shards" : {
    "total" : 0,
    "successful" : 0,
    "failed" : 0
  },
  "_seq_no" : 33,
  "_primary_term" : 3
}

5.4、upsert 元素

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

5.4.1、文档不存在,则创建

入参:

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

出参:

解析:因为ID为2的文档不存在,可以看出执行了创建操作 (“result”:”created”)。

{
  "_index" : "test",
  "_id" : "2",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

5.4.2、文档存在,则执行 Script

入参:

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

出参:

{
  "_index" : "test",
  "_id" : "2",
  "_version" : 4,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

5.5、查询更新

查询更新 API ( _update_by_query ) 的功能是在不更改源的情况 下对索引中的每个文档执行更新。这对于获取新属性或其他联机映射 更改很有用。示例如下:

查询更新过程:

1、_update_by_query 在索引启动时获取索引的快照,并使用 internal 版本控制索引它。这意味着如果文档在拍摄快照的时间和处理索引请求之间发生更改,则会出现版本冲突。当版本匹配时,文档会更新,版本号会递增。

2、所有更新和查询失败都会导致 _update_by_query 中止并 failures 在响应中返回。已执行的更新仍然存在。换句话说,该过程不会回滚,只会中止。

4、当第一个失败导致中止时,失败的批量请求返回的所有失败都将在failures元素中返回; 因此,可能存在相当多的失败实体。

5、如果您只想计算版本冲突,不要导致_update_by_query 中止,您可以 conflicts = proceedURL"conflicts": "proceed" 请求正文中设置。

5.5.1、URL 参数

除了标准的参数,如pretty,此更新通过查询API也支持 refreshwait_for_completionwait_for_active_shardstimeoutscroll

5.5.1.1、refresh

发送将在请求完成时更新正在更新的索引中的所有分片。这与 Index APIrefresh 参数不同,后者仅导致接收新数据的分片被编入索引。

5.5.1.2、wait_for_completion

如果请求包含 wait_for_completion = false,那么 Elasticsearch 将执行一些预检查,启动请求,然后返回一个 Task,以取消或获取任务的状态。Elasticsearch 还将在. asks / task / ${taskId} . 索引中创建此任务的记录文档,可以根据需要保留或删除创建的文档。完成后 删除它,这样 Elasticsearch 可以回收它使用的空间。

5.5.1.3、wait_for_active_shards & timeout

wait_for_active_shards 控制在继续执行请求之前必须激活多少 个shard 副本。

timeout 控制每个写请求等待不可用分片变为可用分片的时间。

这两个参数在 Bulk API中的工作方式完全相同。由于 _update_by_query 操作使用滚动搜索,还可以指定 scroll 参数来控制 “搜索上下文”保持活动的时间,例如 scroll = 10m 。默认为5分钟。

5.5.1.4、requests_per_second

requests_per_second 可以被设置为任何正十进制数(1.461000等)和节流速率 _update_by_query 通过填充每个批次由一等待时间发出索引操作的批次。可以通过设置 requests_per_second为禁用限制-1

通过在批处理之间等待来完成限制,以便在_update_by_query内部使用的滚动 可以被赋予考虑填充的超时。填充时间是批量大小除以requests_per_second写入所花费的时间之间的差异。默认情况下,批处理大小为 1000,因此如果requests_per_second 设置为500

target_time = 1000 / 500 per second = 2 seconds
wait_time = target_time - delete_time = 2 seconds - .5 seconds = 1.5 seconds

5.5.2、请求体

JSON 响应如下

{
  "took" : 147,
  "timed_out": false,
  "total": 5,
  "updated": 5,
  "deleted": 0,
  "batches": 1,
  "version_conflicts": 0,
  "noops": 0,
  "retries": {
    "bulk": 0,
    "search": 0
  },
  "throttled_millis": 0,
  "requests_per_second": -1.0,
  "throttled_until_millis": 0,
  "failures" : [ ]
}:

· :

· :。 · :。 · :。 · :。 · :。 · :。

· :。bulk是重试的批量操作数, search是重试的搜索操作数。

| key | 说明 | | ———————— | ———————————————————— | | took | 整个操作从开始到结束的毫秒数。 | | timed_out | 如果在操作执行期间的任何请求超时,则此标 志设置为true。 | | total | 成功处理的文档数 | | updated | 成功更新的文档数 | | deleted | 成功删除的文档数 | | batches | 分了多少批次执行 | | version_conflicts | 版本冲突的文档数 | | noops | 当设置了ctx.op="noop"时被忽略的文档数 | | retries | 尝试的重试次数 | | bulk | 是重试的批量操作数 | | search | 是重试的搜索操作数 | | throttled_millis | 请求 眠 以 符 合 requests_per_second 的毫秒数。 | | requests_per_second | 每秒有效执行的请求数。 | | throttled_until_millis | 在_update_by_query 响应中,此 字段应始终等于零。<br>只有在使用 TASK AP I时才有意义, 在该 API 中,它指示下一次将再次执行请求的等待时间(从 epoch开始以毫秒为单位),以符合 requests_per_second 参数的限制要求 | | failures | ⬤ 如果请求处理中有任何不可恢复的错误,则记录 到这个失败数组中。如果这不是空的,那么请求会因为这些失败而中止。_update_by_query 是使用批处理实现的,任 何失败都会导致整个过程中止><br/>⬤ 但当前批处理中的所有失败 信息都会收集到数组中。可以使用conflicts 选项防止操作在 版本冲突时中止。 |

5.5.3、任务API

同查询删除 任务API

5.5.4、取消任务API

同查询删除 取消任务API

5.5.5、动态调整API

同查询删除 动态调整API

5.5.6、切片

同查询删除 动态调整API

6、MGet API

MGet API ( _mget ) 基于单个索引、类型(可选)和 ID (可能 还有路由)返回多个文档。响应包括一个 docs数组,其中包含与原始 ` _mget 请求相对应的所有已提取文档(如果特定Get 失败,则在响应 中包含此错误的对象)。成功的 Get 的结构与Get AP`I提供的文档在结 构上类似。示例如下:

6.1、普通查询

入参:

GET _mget
{
    "docs": [
        {
            "_index": "example",
            "_id": "1"
        },
        {
            "_index": "example",
            "_id": "2"
        },
        {
            "_index": "example_test",
            "_id": "1"
        },
        {
            "_index": "example_test",
            "_id": "2"
        }
    ]
}


6.2、指定索引查询

_mget 请求也可以用于指定索引(在这种情况下,主体中不需要 它)

入参:

GET test/_doc/_mget
{
    "docs": [
        {
            "_id": "1"
        },
        {
            "_id": "2"
        },
        {
            "_id": "1"
        },
        {
            "_id": "2"
        }
    ]
}

6.2.1、简化查询

可以直接使用 ids 元素来简化请求:

入参:

GET test/_mget
{
    "ids": ["1", "2"]
}

6.3、_source 过滤

默认情况下,将为每个文档返回_source字段(如果已存储)。 与 Get API类似,可以使用 _source 参数仅检索 _source 的部分内容 ( 或 者 根 本 不 检 索 ) , 还 可 以 使 用 URL 参 数 _source_source_includes_source_excludes 指定默认值。示例如下:

入参:

GET /_mget
{
    "docs" : [
        {
            "_index" : "test",
            "_id" : "1",
            "_source" : false
        },
        {
            "_index" : "test",
            "_id" : "2",
            "_source" : ["field3", "field4"]
        },
        {
            "_index" : "test",
            "_id" : "3",
            "_source" : {
                "include": ["user"],
                "exclude": ["user.location"]
            }
        }
    ]
}

6.4、存储字段

可以为每个要获取的文档指定检索特定存储字段( store 属性为 true ),类似于 Get APIstored_fields 参数。例如:

6.4.1、请求体指定

入参:

GET /_mget
{
    "docs" : [
        {
            "_index" : "test",
            "_id" : "1",
            "stored_fields" : ["field1", "field2"]
        },
        {
            "_index" : "test",
            "_id" : "2",
            "stored_fields" : ["field3", "field4"]
        }
    ]
}

6.4.2、URL 中指定

可以在查询字符串中指定 stored_fields 参数作为默认值, 应用于所有文档

入参:

GET /test/_doc/_mget?stored_fields=field1,field2
{
    "docs" : [
        {
            "_id" : "1"  
        },
        {
            "_id" : "2",
            "stored_fields" : ["field3", "field4"]
        }
    ]
}

6.5、路由

可以将路由值作为参数

举例:

1、文档 test/_doc/2 将从路由键key1 对应的分片中获取,

2、文档 test/_doc/1 将从路由键 key2对应的分片中提取,因为 test/_doc/2 没有单独指定路由。

入参:

GET /_mget?routing=key1
{
    "docs" : [
        {
            "_index" : "test",
            "_id" : "1",
            "routing" : "key2"
        },
        {
            "_index" : "test",
            "_id" : "2"
        }
    ]
}

7、bulk 批量操作

批量操作API ( _bulk ) 可以在单个 API 调用中执行多个索引和删 除操作。这可以大大提高索引速度

bulk apijson 的语法,有严格的要求,每个 json 串不能换行,只能放一行,同时一个 json 串和一个 json 串之间,必须有一个换行

bulk 操作中,任意一个操作失败,是不会影响其他的操作的,但是在返回结果里,会告诉你异常日志

bulk size 最佳大小:bulk request 会加载到内存里,如果太大的话,性能反而会下降,因此需要反复尝试一个最佳的 bulk size-。一般从1000-5000条数据开始,尝试逐渐增加。另外,如果看大小的话,最好是在5-15MB 之间。

7.1、简单操作

入参:

POST _bulk
{"delete":{"_index":"megacorp","_id":30}}
{"create":{"_index":"megacorp","_id":5}}
{"first_name":"John","last_name":"Smith","age":25,"about":"I love to go rock climbing","interests":["sports","music"]}
{"create":{"_index":"megacorp","_id":6}}
{"first_name":"John","last_name":"Smith","age":25,"about":"I love to go rock climbing","interests":["sports","music"]}
{"index":{"_index":"megacorp","_id":7}}
{"first_name":"John","last_name":"Smith","age":25,"about":"I love to go rock climbing","interests":["sports","music"]}
{"index":{"_index":"megacorp","_id":8}}
{"first_name":"John","last_name":"Smith","age":25,"about":"I love to go rock climbing","interests":["sports","music"]}
{"update":{"_index":"megacorp","_id":1}}
{"doc":{"age":55}}

出参:

{
  "took" : 29,
  "errors" : true,
  "items" : [
    {
      "delete" : {
        "_index" : "megacorp",
        "_id" : "30",
        "_version" : 1,
        "result" : "not_found",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 5,
        "_primary_term" : 1,
        "status" : 404
      }
    },
    {
      "create" : {
        "_index" : "megacorp",
        "_id" : "5",
        "status" : 409,
        "error" : {
          "type" : "version_conflict_engine_exception",
          "reason" : "[5]: version conflict, document already exists (current version [1])",
          "index_uuid" : "n8I5TI3SQDuVuFoLuPxvnw",
          "shard" : "0",
          "index" : "megacorp"
        }
      }
    },
    {
      "create" : {
        "_index" : "megacorp",
        "_id" : "6",
        "status" : 409,
        "error" : {
          "type" : "version_conflict_engine_exception",
          "reason" : "[6]: version conflict, document already exists (current version [1])",
          "index_uuid" : "n8I5TI3SQDuVuFoLuPxvnw",
          "shard" : "0",
          "index" : "megacorp"
        }
      }
    },
    {
      "index" : {
        "_index" : "megacorp",
        "_id" : "7",
        "_version" : 2,
        "result" : "updated",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 6,
        "_primary_term" : 1,
        "status" : 200
      }
    },
    {
      "index" : {
        "_index" : "megacorp",
        "_id" : "8",
        "_version" : 2,
        "result" : "updated",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 7,
        "_primary_term" : 1,
        "status" : 200
      }
    },
    {
      "update" : {
        "_index" : "megacorp",
        "_id" : "1",
        "status" : 404,
        "error" : {
          "type" : "document_missing_exception",
          "reason" : "[1]: document missing",
          "index_uuid" : "n8I5TI3SQDuVuFoLuPxvnw",
          "shard" : "0",
          "index" : "megacorp"
        }
      }
    }
  ]
}

7.2、指定索引操作

如果只是操作同一个索引可以想 mget 一样指定索引

入参:

POST /megacorp/_bulk
{"delete":{"_id":30}}
{"delete":{"_id":31}}
{"delete":{"_id":32}}

7.3、路由

每个批量项目都可以使用 routing 字段传递路由值。它会根据 _routing映射自动跟踪索引和删除操作的行为。

7.4、批量更新

当使用更新操作时,retry_on_conflict 可以用作操作本身(不在额外的有效负载行中)中的字段,以指定在发生版本冲突时应重试更 新的次数。

Update 操作支持以下选项 :doc (部分文档)、upsertdoc_as_upsertscriptparams用于脚本)、lang(用于脚本) 和_source。更新操作示例如下:

POST _bulk
{ "update" : {"_id" : "1", "_index" : "index1", "retry_on_conflict" : 3} }
{ "doc" : {"field" : "value"} }
{ "update" : { "_id" : "0", "_index" : "index1", "retry_on_conflict" : 3} }
{ "script" : { "source": "ctx._source.counter += params.param1", "lang" : "painless", "params" : {"param1" : 1}}, "upsert" : {"counter" : 1}}
{ "update" : {"_id" : "2", "_index" : "index1", "retry_on_conflict" : 3} }
{ "doc" : {"field" : "value"}, "doc_as_upsert" : true }
{ "update" : {"_id" : "3", "_index" : "index1", "_source" : true} }
{ "doc" : {"field" : "value"} }
{ "update" : {"_id" : "4", "_index" : "index1"} }
{ "doc" : {"field" : "value"}, "_source": true}

8、Term 向量

Term 向量 ( Term Vectors ) 用来存储文档字段的 Term 信息(字段文本分词得到的词条)和统计信息。文档可以存储在索引中,也可 以由用户人工提供。Term 向量在默认情况下是实时的。这可以通过将 realtime 参数设置为 false来更改。

8.1、返回值

可以请求三种类型的值 : Term 信息、Term 统计信息和字段统计信息。默认情况下,返回所有字段的所有 Term信息和字段统计信息, 但不返回Term统计信息。

8.1.1、Term 信息

Term 的频率 ( 在对应字段中 ) ,这部分信息是始终返回的。

Term 的位置,需要设置 positions : true

Term 开始和结束的偏移量,需要设置 offsets : true

Term Payloads (有效载荷,请参考Lucene相关文档), 需要设置payloads : true

注意:如果请求的信息没有存储在索引中,如果可能它将被即时计算。另外,对于甚至不存在于索引中但由用户提供的文档,也可以计算词条向量。

警告:开始与结束的偏移量假设 UTF - 16 编码被使用。如果要使用这些偏移量来从原始文本中获取词条,则应确保使用UTF - 16 对正在使用的子字符串进行编码。

Term 信息在 Elasticsearch 中的具体存储格式如图

image-20220609172637910

8.1.2、字段统计信息

字段统计信息默认是返回的,可以将 field_statistics 设为 false 来 禁止返回。字段统计信息包括如下三方面的内容:

⬤ 文档计数,即多少个文档存在这个字段值。

⬤ 文档频率总和,即此字段中所有 Term 的文档频率总和。

Term 频率总和,即该字段中每个 Term 的总项频率之和

8.1.3、Term 过滤

使用参数 filter ,还可以根据 tf - idf 分数过滤返回的 Term。这有助 于找出文档的特征向量。此功能的工作方式更类似于此查询的第二阶 段。

样例:在下面的示例中,从具有给定 plot 字段值的文档中获得三个用户 “最感兴趣”的关键字。请注意,关键字 Tony 或任何停止词都不是响 应的一部分,因为它们的 tf - idf 太低。

入参:

GET /imdb/_termvectors
{
    "doc": {
      "plot": "When wealthy industrialist Tony Stark is forced to build an armored suit after a life-threatening incident, he ultimately decides to use its technology to fight against evil."
    },
    "term_statistics" : true,
    "field_statistics" : true,
    "positions": false,
    "offsets": false,
    "filter" : {
      "max_num_terms" : 3,
      "min_term_freq" : 1,
      "min_doc_freq" : 1
    }
}

出参:

{
   "_index": "imdb",
   "_type": "movies",
   "_version": 0,
   "found": true,
   "term_vectors": {
      "plot": {
         "field_statistics": {
            "sum_doc_freq": 3384269,
            "doc_count": 176214,
            "sum_ttf": 3753460
         },
         "terms": {
            "armored": {
               "doc_freq": 27,
               "ttf": 27,
               "term_freq": 1,
               "score": 9.74725
            },
            "industrialist": {
               "doc_freq": 88,
               "ttf": 88,
               "term_freq": 1,
               "score": 8.590818
            },
            "stark": {
               "doc_freq": 44,
               "ttf": 47,
               "term_freq": 1,
               "score": 9.272792
            }
         }
      }
   }
}

8.1.3.1、子参数

key 说明
max_num_terms 每个字段返回的最大Term数。默认值 为25。也就是只有一个字段最多 25 个Term
min_term_freq 忽略源文档中低于此频率的单词。默认值 为1。
max_term_freq 忽略源文档中超过此频率的单词。默认为 无限大
min_doc_freq 忽略文档频率低于这个值的 Term。默认值 为1。
max_doc_freq 忽略文档频率高于这个值的Term。默认值 为1。
min_word_length 忽略低于此值的Term。默认值为0。
max_word_length 忽略高于此值的Term。默认值为无穷 大。

8.2、行为分析

TermField 统计信息是不准确的,仅检索请求文档所在的分片 的信息,而删除的文档不考虑在内。

因此,TermField 统计信息仅 用作相对测量,而绝对数值在此上下文中没有意义。默认情况下,当 请求人工文档的 Term 向量时,将随机选择一个分片来获取统计信息。 使用 routing 只命中特定的分片。

8.2.1、返回存储词条向量

8.2.1.1、创建一个存储词条向量、有效载荷等的索引

入参:

PUT /twitter
{ "mappings": {
    "properties": {
      "text": {
        "type": "text",
        "term_vector": "with_positions_offsets_payloads",
        "store" : true,
        "analyzer" : "fulltext_analyzer"
       },
       "fullname": {
        "type": "text",
        "term_vector": "with_positions_offsets_payloads",
        "analyzer" : "fulltext_analyzer"
      }
    }
  },
  "settings" : {
    "index" : {
      "number_of_shards" : 1,
      "number_of_replicas" : 0
    },
    "analysis": {
      "analyzer": {
        "fulltext_analyzer": {
          "type": "custom",
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "type_as_payload"
          ]
        }
      }
    }
  }
}

出参:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "twitter"
}

8.2.1.2、添加一些文档:

入参:

PUT /twitter/_doc/1
{
  "fullname" : "John Doe",
  "text" : "twitter test test test "
}
 
PUT /twitter/_doc/2
{
  "fullname" : "Jane Doe",
  "text" : "Another twitter test ..."
}

出参:

# PUT /twitter/_doc/1
{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

# PUT /twitter/_doc/2
{
  "_index" : "twitter",
  "_id" : "2",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

8.2.1.3、返回Id=1 中字段text的所有信息和统计信息:

入参:

GET /twitter/_termvectors/1
{
  "fields" : ["text"],
  "offsets" : true,
  "payloads" : true,
  "positions" : true,
  "term_statistics" : true,
  "field_statistics" : true
} 

出参:

{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 2,
  "found" : true,
  "took" : 3,
  "term_vectors" : {
    "text" : {
      "field_statistics" : {
        "sum_doc_freq" : 6,
        "doc_count" : 2,
        "sum_ttf" : 8
      },
      "terms" : {
        "test" : {
          "doc_freq" : 2,
          "ttf" : 4,
          "term_freq" : 3,
          "tokens" : [
            {
              "position" : 1,
              "start_offset" : 8,
              "end_offset" : 12,
              "payload" : "d29yZA=="
            },
            {
              "position" : 2,
              "start_offset" : 13,
              "end_offset" : 17,
              "payload" : "d29yZA=="
            },
            {
              "position" : 3,
              "start_offset" : 18,
              "end_offset" : 22,
              "payload" : "d29yZA=="
            }
          ]
        },
        "twitter" : {
          "doc_freq" : 2,
          "ttf" : 2,
          "term_freq" : 1,
          "tokens" : [
            {
              "position" : 0,
              "start_offset" : 0,
              "end_offset" : 7,
              "payload" : "d29yZA=="
            }
          ]
        }
      }
    }
  }
}

8.2.1.4、自动生成词条向量

未明确存储在索引中的词条向量将自动计算。以下请求返回文档 1 中字段的所有信息和统计信息,即使词条尚未明确存储在索引中。请注意,对于字段 text,术语不会重新生成。

入参:

GET /twitter/_termvectors/1
{
  "fields" : ["text", "some_field_without_term_vectors"],
  "offsets" : true,
  "positions" : true,
  "term_statistics" : true,
  "field_statistics" : true
} 

出参:

{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 2,
  "found" : true,
  "took" : 2,
  "term_vectors" : {
    "text" : {
      "field_statistics" : {
        "sum_doc_freq" : 6,
        "doc_count" : 2,
        "sum_ttf" : 8
      },
      "terms" : {
        "test" : {
          "doc_freq" : 2,
          "ttf" : 4,
          "term_freq" : 3,
          "tokens" : [
            {
              "position" : 1,
              "start_offset" : 8,
              "end_offset" : 12,
              "payload" : "d29yZA=="
            },
            {
              "position" : 2,
              "start_offset" : 13,
              "end_offset" : 17,
              "payload" : "d29yZA=="
            },
            {
              "position" : 3,
              "start_offset" : 18,
              "end_offset" : 22,
              "payload" : "d29yZA=="
            }
          ]
        },
        "twitter" : {
          "doc_freq" : 2,
          "ttf" : 2,
          "term_freq" : 1,
          "tokens" : [
            {
              "position" : 0,
              "start_offset" : 0,
              "end_offset" : 7,
              "payload" : "d29yZA=="
            }
          ]
        }
      }
    }
  }
}

8.2.1.5、人造文档

还可以为人造文档生成词条向量,也就是生成索引中不存在的文档。

入参:

GET /twitter/_termvectors
{
  "doc" : {
    "fullname" : "John Doe",
    "text" : "twitter test test test"
  }
} 

出参:

{
  "_index" : "twitter",
  "_version" : 0,
  "found" : true,
  "took" : 111,
  "term_vectors" : {
    "fullname" : {
      "field_statistics" : {
        "sum_doc_freq" : 4,
        "doc_count" : 2,
        "sum_ttf" : 4
      },
      "terms" : {
        "doe" : {
          "term_freq" : 1,
          "tokens" : [
            {
              "position" : 1,
              "start_offset" : 5,
              "end_offset" : 8
            }
          ]
        },
        "john" : {
          "term_freq" : 1,
          "tokens" : [
            {
              "position" : 0,
              "start_offset" : 0,
              "end_offset" : 4
            }
          ]
        }
      }
    },
    "text" : {
      "field_statistics" : {
        "sum_doc_freq" : 6,
        "doc_count" : 2,
        "sum_ttf" : 8
      },
      "terms" : {
        "test" : {
          "term_freq" : 3,
          "tokens" : [
            {
              "position" : 1,
              "start_offset" : 8,
              "end_offset" : 12
            },
            {
              "position" : 2,
              "start_offset" : 13,
              "end_offset" : 17
            },
            {
              "position" : 3,
              "start_offset" : 18,
              "end_offset" : 22
            }
          ]
        },
        "twitter" : {
          "term_freq" : 1,
          "tokens" : [
            {
              "position" : 0,
              "start_offset" : 0,
              "end_offset" : 7
            }
          ]
        }
      }
    }
  }
}

8.2.1.6、字段分析器

此外,可以使用 per_field_analyzer 参数为不同的字段提供不同 的分析器,这对于以任何方式生成 Term 向量都很有用,特别是在使用 人工文档时。当为已经存储 Term 向量的字段提供分析器时,将重新生成 Term 向量。

入参:

GET /twitter/_termvectors
{
  "doc" : {
    "fullname" : "John Doe",
    "text" : "twitter test test test"
  },
  "fields": ["fullname"],
  "per_field_analyzer" : {
    "fullname": "keyword"
  }
} 

出参:

{
  "_index" : "twitter",
  "_version" : 0,
  "found" : true,
  "took" : 2,
  "term_vectors" : {
    "fullname" : {
      "field_statistics" : {
        "sum_doc_freq" : 4,
        "doc_count" : 2,
        "sum_ttf" : 4
      },
      "terms" : {
        "John Doe" : {
          "term_freq" : 1,
          "tokens" : [
            {
              "position" : 0,
              "start_offset" : 0,
              "end_offset" : 8
            }
          ]
        }
      }
    }
  }
}

9、refresh 参数

索引、更新、删除和批量 API 支持用 refresh 参数来控制请求所做 的更改何时对搜索可见。允许的值如下。

9.1、参数配置

9.1.1、空或 true

操作发生后立即刷新相关的主分片和副本分片 (不是整个索引),以便更新的文档立即显示在搜索结果中。这个设置需要仔细考虑和验证,因为会导致性能下降(从索引和搜索的角度来看)

PUT /test/_doc/1?refresh
{"test":"test"}
PUT /test/_doc/2?refresh=true
{"test":"test"}

9.1.2、wait_for

在返回结果之前,将等待刷新使请求所做的更改可见,这不会强制立即刷新,而是等待刷新发生。

Elasticsearch自动刷新,刷新频率是 index.refresh_interval,默认是 1s。这个设置是动态的。调用 refresh API,或在响应的 API 上设置 refreshtrue 都将导致刷新,请求将返回。

PUT /test/_doc/3
{"test":"test"}

PUT /test/_doc/4?refresh=false
{"test":"test"}

9.1.3、false (默认值)

不执行与刷新相关的操作。此请求所做的更改将在请求返回后的某个时间点可见

PUT /test/_doc/4?refresh=wait_for
{"test":"test"}

9.2、如何选择refresh的值

除非有充分的理由等待更改变为可见,否则始终使用 refresh = false

如果必须使请求所做的更改与请求同步可见 当

⬤ 设置refresh 为 ` true 时,Elasticsearch` 将增加更多负载

⬤ 设置为 wait_for ;将等待更 长时间,这需要结合实际情况决定。

9.3、强制刷新

如果当已经有 index.max_refresh_listeners 值定义数量 ( 默认 为 1000 个) 的请求在该分片上等待刷新时,该请求的行为将如同 refresh 设置为true 一样:它将强制刷新。这保证了当该请求返回时, 其更改对搜索可见,同时防止对被阻塞的请求使用未经检查的资源。 如果请求由于监听器槽用完而强制刷新,则其 响应将包含”forced_refresh”: true 信息。

10、乐观并发控制

Elasticsearch是分布式的,创建、更新或删除文档时,必须将文档的新版本复制到集群中的其他节点。Elasticsearch也是异步和并发的,这意味着这些复制请求是并行发送的,并且可能不按顺序到达目的地。Elasticsearch需要一种方法来确保旧版本的文档永远不会覆盖新版本的文档。

保证并发:为了确保旧版本的文档不会覆盖新版本文档,对文档执行的每个操作都由主分片分配一个序列号,序列号随着每个操作的增加而增加,因此新操作的序列号肯定比旧操作的序列号更高。然后, Elasticsearch可以使用这个序列号来确保新的文档版本不会被分配了较小序列号的更改覆盖。

举例:以下索引命令将创建一个文档并为其分配初始序列号 _seq_no_primary_term ( _primary_term_seq_no 都 是 整 数),每当主分片发生重新分配时,比如重启、Primary 选举等, _primary_term 会递增1:

入参:

GET twitter/_doc/1

出参:

{
  "_index" : "twitter",
  "_id" : "1",
  "_version" : 14,
  "_seq_no" : 15,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "fullname" : "John Doe",
    "text" : "twitter test test test "
  }
}

10.1、乐观更新

_seq_no_primary_term唯一地标识一个变更。通过记下返回 的这两个值,可以确保仅在检索文档后没有对其进行其他更改的情况 下更改文档。这是通过设置索引 API 或删除 APIif_seq_noif_primary_term 参数来完成的

例如,以下调用将确保向文档中添加标记 tag,而不会丢失对描述 的任何潜在更改或由其他API添加其他标记:

入参:

PUT /products/_doc/1567?if_seq_no=362&if_primary_term=2
{
    "product" : "r2d2",
    "details" : "A resourceful astromech droid",
    "tags": ["droid"]
}
'

ContactAuthor

 

 
 

r