Elasticsearch 基础文档学习

发布于 2024-11-02 20:13:12 字数 27923 浏览 9 评论 0

Elasticsearch 是一个实时的分布式搜索分析引擎,它能让你以一个之前从未有过的速度和规模,去探索你的数据。 它被用作 全文检索结构化搜索分析 以及这三个功能的 组合 . Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上。 Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库. Elasticsearch 的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单,通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API.你可以这样来形容 Elasticsearch

  • 一个分布式的实时文档存储,每个字段可以被索引与搜索
  • 一个分布式实时分析搜索引擎
  • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据

Elasticsearch 安装依赖与 JavaElasticsearch ,安装完运行 curl 'http://localhost:9200/?pretty' 测试安装时候成功.一个 Elasticsearch 集群是一组拥有相同 cluster.name 的节点,他们能一起工作并共享数据,还提供容错与可伸缩性。你可以在 elasticsearch.yml 配置文件中 修改 cluster.name ,该文件会在节点启动时加载 (译者注:这个重启服务后才会生效)

Sense 是一个 Kibana 应用 它提供交互式的控制台,通过你的浏览器直接向 Elasticsearch 提交请求。 这本书的在线版本包含有一个 View in Sense 的链接,里面有许多代码示例。当点击的时候,它会打开一个代码示例的 Sense 控制台。 你不必安装 Sense,但是它允许你在本地的 Elasticsearch 集群上测试示例代码,从而使本书更具有交互性

elasticsearch 交互

Elasticsearch 的交互方式取决于 你是否使用 Java ,

  • JAVA API

    如果你正在使用 Java,在代码中你可以使用 Elasticsearch 内置的两个客户端:

    • 节点客户端 Node client
      节点客户端作为一个非数据节点加入到本地集群中。换句话说,它本身不保存任何数据,但是它知道数据在集群中的哪个节点中,并且可以把请求转发到正确的节点。
    • 传输客户端 Transport client
      轻量级的传输客户端可以将请求发送到远程集群。它本身不加入集群,但是它可以将请求转发到集群中的一个节点上。

    两个 Java 客户端都是通过 9300 端口并使用本地 Elasticsearch 传输 协议和集群交互。集群中的节点通过端口 9300 彼此通信。如果这个端口没有打开,节点将无法形成一个集群。Java 客户端作为节点必须和 Elasticsearch 有相同的 主要 版本

  • RESTful API with JSON over HTTP

所有其他语言可以使用 RESTful API 通过端口 9200Elasticsearch 进行通信,你可以用你最喜爱的 web 客户端访问 Elasticsearch 。事实上,正如你所看到的,你甚至可以使用 curl 命令来和 Elasticsearch 交互

一个 Elasticsearch 请求和任何 HTTP 请求一样由若干相同的部件组成:
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>' ,被 < > 标记的部件:

参数含义
VERB适当的 HTTP 方法 或 谓词 : GETPOSTPUTHEAD 或者 DELETE
PROTOCOLhttp 或者 https (如果你在 Elasticsearch 前面有一个 https 代理)
HOSTElasticsearch 集群中任意节点的主机名,或者用 localhost 代表本地机器上的节点
PORT运行 Elasticsearch HTTP 服务的端口号,默认是 9200
PATHAPI 的终端路径(例如 _count 将返回集群中文档数量)。Path 可能包含多个组件,例如:_cluster/stats 和 _nodes/stats/jvm
QUERY_STRING任意可选的查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读)
BODY一个 JSON 格式的请求体 (如果请求需要的话)

例如,计算集群中文档的数量,我们可以用这个:

curl -XGET 'http://localhost:9200/_count?pretty'  -d '
{
    "query": {
        "match_all": {}
    }
}
'

要查看头信息需要加一个 i 参数: curl -i -XGET

面向文档

在应用程序中对象很少只是一个简单的键和值的列表。通常,它们拥有更复杂的数据结构,可能包括日期、地理信息、其他对象或者数组等.也许有一天你想把这些对象存储在数据库中。使用 关系型数据库 的行和列存储,这相当于是把一个表现力丰富的对象挤压到一个非常大的电子表格中. Elasticsearch面向文档 的,意味着它存储整个对象或 文档_ ,Elasticsearch 不仅存储文档,而且 _索引 每个文档的内容使之可以被检索。在 Elasticsearch 中,你 对文档进行索引、检索、排序和过滤--而不是对行列数据。这是一种完全不同的思考数据的方式,也是 Elasticsearch 能支持复杂全文检索的原因.在 Elasticsearch 中将对象转化为 JSON 并做索引要比在一个扁平的表结构中做相同的事情简单的多

基础入门

一个简单例子

# 要实现的例子
创建一个雇员目录编辑
我们受雇于 Megacorp 公司,作为 HR 部门新的 “热爱无人机” (_"We love our drones!"_)激励项目的一部分,我们的任务是为此创建一个雇员目录。该目录应当能培养雇员认同感及支持实时、高效、动态协作,因此有一些业务需求:

* 支持包含多值标签、数值、以及全文本的数据
* 检索任一雇员的完整信息
* 允许结构化搜索,比如查询 30 岁以上的员工
* 允许简单的全文搜索以及较复杂的短语搜索
* 支持在匹配文档内容中高亮显示搜索片段
* 支持基于数据创建和管理分析仪表盘

索引员工信息

存储雇员数据,以 雇员文档 的形式存储:一个文档代表一个雇员。存储数据到 Elasticsearch 的行为叫做 索引 .一个 Elasticsearch 集群可以 包含多个 索引 ,相应的每个索引可以包含多个 类型 。 这些不同的类型存储着多个 文档 ,每个文档又有多个 属性

  • 和关系型数据库的对应关系
ESRDBMS
索引(名词)数据库
类型表名
文档记录
属性字段

你也许已经注意到 索引 这个词在 Elasticsearch 语境中包含多重意思, 所以有必要做一点儿说明:
索引(名词)
如前所述,一个 索引 类似于传统关系数据库中的一个 数据库 ,是一个存储关系型文档的地方。 索引 (index) 的复数> 词为 indices 或 indexes 。
索引(动词)
索引一个文档 就是 存储 一个文档到一个 索引 (名词)中以便它可以被检索和查询到。这非常类似于 SQL 语句中的 INSERT 关键词,除了文档已存在时新文档会替换旧文档情况之外。
倒排索引
关系型数据库通过增加一个 索引 比如一个 B 树(B-tree)索引 到指定的列上,以便提升数据检索速度。> Elasticsearch 和 Lucene 使用了一个叫做 倒排索引 的结构来达到相同的目的。
+ 默认 的,一个文档中的 每一个属性都是被索引的 (有一个倒排索引)和可搜索的。一个没有倒排索引的属性是不能被搜索到的。我们将在 倒排索引 讨论倒排索引的更多细节。

索引一个文档进索引的例子: curl -XPUT 'localhost:9200/megacorp/employee/1?pretty' -H 'Content-Type: application/json' -d' {"first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ]}'

  • 每个雇员 索引一个文档 ,包含该雇员的所有信息
  • 每个文档都将是 employee 类型
  • 该类型位于 索引 megacorp 内
  • 1 特定雇员的 ID

检索文档

我们已经在 Elasticsearch 中存储了一些数据, 接下来就能专注于实现应用的业务需求了。第一个需求是可以 检索 到单个雇员的数据. curl -XGET 'localhost:9200/megacorp/employee/1?pretty'

  • TIP
    将 HTTP 命令由 PUT 改为 GET 可以用来检索文档,同样的,可以使用 DELETE 命令来删除文档,以及使用 HEAD 指令来检查文档是否存在。如果想更新已存在的文档,只需再次 PUT

轻量搜索

  • 搜索 megacorp 索引, employee 类型的所有雇员 curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' : 默认显示 10 条数据
  • 搜索姓氏为 Smith 的雇员(方法一般涉及到一个 查询字符串(query-string) 搜索): curl -XGET 'localhost:9200/megacorp/employee/_search?q=last_name:Smith&pretty'

使用查询表达式搜索

使用查询字符串(query-string) 搜索简单方便,但是有自身的局限性, 轻量搜索的弊端 .更加复杂的检索可以用 查询表达式搜索

# match 查询. 属于查询类型之一
curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "query" : {
        "match" : {
            "last_name" : "Smith"
        }
    }
}
'

更加复杂的查询

尝试下更复杂的搜索。 同样搜索姓氏为 Smith 的雇员,但这次我们只需要年龄大于 30 的

curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "query" : {
        "bool": {
            "must": {
                "match" : {
                    "last_name" : "smith"
                }
            },
            "filter": {
                "range" : {
                    "age" : { "gt" : 30 }
                }
            }
        }
    }
}
'

全文检索

目前的搜索相对都很简单:单个姓名,通过年龄过滤。现在尝试下稍微高级点儿的 全文搜索 ——一项传统数据库确实很难搞定的任务

curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "query" : {
        "match" : {
            "about" : "rock climbing"
        }
    }
}
'

Elasticsearch 默认按照 相关性得分 排序,即每个文档跟查询的匹配程度。第一个最高得分的结果很明显:John Smith 的 about 属性清楚地写着 “rock climbing”.但为什么 Jane Smith 也作为结果返回了呢?原因是她的 about 属性里提到了 “rock” 。因为只有 “rock” 而没有 “climbing” ,所以她的相关性得分低于 John 的.这是一个很好的案例,阐明了 Elasticsearch 如何 在 全文属性上搜索并返回相关性最强的结果。Elasticsearch 中的 相关性 概念非常重要,也是完全区别于传统关系型数据库的一个概念,数据库中的一条记录要么匹配要么不匹配

短语搜索

找一个属性中的独立单词是没有问题的,但有时候想要精确匹配一系列单词或者短语.比如,我们想执行这样一个查询,仅匹配 同时 包含 “rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式 紧挨着 的雇员记录, match_phrase

curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    }
}
'

高亮搜索

许多应用都倾向于在每个搜索结果中 高亮 官网关于高亮搜索片段 部分文本片段,以便让用户知道为何该文档符合查询条件.在 Elasticsearch

curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "query" : {
        "match_phrase" : {
            "about" : "rock climbing"
        }
    },
    "highlight": {
        "fields" : {
            "about" : {}
        }
    }
}
'

分析

最后一个业务需求:支持管理者对雇员目录做分析. Elasticsearch 有一个功能叫聚合 aggregations

# 挖掘出雇员中最受欢迎的兴趣爱好
curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "aggs": {
    "all_interests": {
      "terms": { "field": "interests" }
    }
  }
}
'

# 特定的条件下的聚合, 匹配符合一定条件的聚合结果
curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "last_name": "smith"
    }
  },
  "aggs": {
    "all_interests": {
      "terms": {
        "field": "interests"
      }
    }
  }
}
'

# 聚合还支持分级汇总 比如,查询特定兴趣爱好员工的平均年龄
curl -XGET 'localhost:9200/megacorp/employee/_search?pretty' -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "all_interests" : {
            "terms" : { "field" : "interests" },
            "aggs" : {
                "avg_age" : {
                    "avg" : { "field" : "age" }
                }
            }
        }
    }
}
'
# 输出基本是第一次聚合的加强版。依然有一个兴趣及数量的列表,只不过每个兴趣都有了一个附加的 avg_age 属性,代表有这个兴趣爱好的所有员工的平均年龄

分布式特点

Elasticsearch 天生就是分布式的,并且在设计时 屏蔽 了分布式的复杂性。 Elasticsearch 在分布式方面几乎是 透明 的。教程中并不要求了解分布式系统、分片、集群发现或其他的各种分布式概念。可以使用笔记本上的单节点轻松地运行教程里的程序,但如果你想要在 100 个节点的集群上运行程序,一切依然顺畅。
Elasticsearch 尽可能地屏蔽了分布式系统的复杂性。这里列举了一些在后台自动执行的操作:

  • 分配文档到不同的容器 或 分片 中,文档可以储存在一个或多个节点中
  • 按集群节点来均衡分配这些分片,从而对索引和搜索过程进行负载均衡
  • 复制每个分片以支持数据冗余,从而防止硬件故障导致的数据丢失
  • 将集群中任一节点的请求路由到存有相关数据的节点
  • 集群扩容时无缝整合新节点,重新分配分片以便从离群节点恢复

当阅读本书时,将会遇到有关 Elasticsearch 分布式特性的补充章节。这些章节将介绍有关集群扩容、故障转移( 官网-集群内的原理 ) 、应对文档存储( 官网-分布式文档存储 ) 、执行分布式搜索( 官网-执行分布式检索 ) ,以及分区(shard)及其工作原理( 官网-分片内部原理 )

集群内的原理

跳过

数据输入和输出

一个 对象 是基于特定语言的内存的数据结构。为了通过网络发送或者存储它,我们需要将它表示成某种标准的格式。JSON 是一种以人可读的文本表示对象的方法。它已经变成 NoSQL 世界交换数据的事实标准。当一个对象被序列化成为 JSON,它被称为一个 JSON 文档.在本章中,我们展示了用来创建,检索,更新和删除文档的 API

文档元数据

一个文档不仅仅包含它的数据,也包含 元数据 有关文档的信息。三个必须的元数据元素如下:

  • _index : 属于那个文档, 文档在哪存放.一个 索引 应该是因共同的特性被分组到一起的文档集合。例如,你可能存储所有的产品在索引 products 中,而存储所有销售的交易到索引 sales 中.实际上,在 Elasticsearch 中,我们的数据是被存储和索引在 分片 中,而一个索引仅仅是 逻辑上 的命名空间,这个命名空间由一个或者多个分片组合在一起。然而,这是一个内部细节,我们的应用程序根本不应该关心分片,对于应用程序而言,只需知道文档位于一个索引内。Elasticsearch 会处理所有的细节. 索引名 必须小写,不能以下划线开头,不能包含逗号
  • _type : 文档表示的对象类别. 索引中只是松散的组合在一起,但是通常明确定义一些数据中的子分区是很有用的. 文档共享一种相同的(或非常相似)的模式:他们有一个标题、描述、产品代码和价格. 类型名 大写或者小写,但是不能以下划线或者句号开头,不应该包含逗号,并且长度限制为 256 个字符
  • _id : 文档唯一标识. 它和 _index 以及 _type 组合就可以唯一确定 Elasticsearch 中的一个文档

索引文档

一个文档的 _index_type_id 唯一标识一个文档

  • 使用自定义的 ID put + 指定 id
curl -XPUT 'localhost:9200/website/blog/123?pretty' -H 'Content-Type: application/json' -d'
{
  "title": "My first blog entry",
  "text":  "Just trying this out...",
  "date":  "2014/01/01"
}
'
# 成功后会输出一个新字段`_version`每个文档都有一个版本号
  • 自动生成 ID post 不加 id
curl -XPOST 'localhost:9200/website/blog/?pretty' -H 'Content-Type: application/json' -d'
{
  "title": "My second blog entry",
  "text":  "Still trying this out...",
  "date":  "2014/01/01"
}
'

取回一个文档

# 加上 pretty 参数,将会调用 Elasticsearch 的 pretty-print 功能,使得 JSON 响应体更加可读
# -i 参数会增加文件的响应头
curl -XGET 'localhost:9200/website/blog/123?pretty&pretty'
# 响应体包括 {"found": true} ,这证实了文档已经被找到. 不存在 found 将会是 false
  • 返回文档的部分
# 单个字段能用 _source 参数请求得到,多个字段也能使用逗号分隔的列表来指定
curl -XGET 'localhost:9200/website/blog/123?_source=title,text&pretty'
  • 除了 source 数据不想要任何元数据
curl -XGET 'localhost:9200/website/blog/123/_source?pretty'

检查文档是否存在

  • 只关心文档是否存在,不关心里面的内容
# 用 HEAD 方法来代替 GET 方法。 HEAD 请求没有返回体,只返回一个 HTTP 请求报头
curl -i -XHEAD http://localhost:9200/website/blog/123 

更新整个文档

Elasticsearch 中文档是 不可改变 的,不能修改它们。相反,如果想要 更新现有的文档 ,需要 重建索引 或者进行替换,我们可以使用相同的 index API 进行实现,在索引文档中已经进行了讨论

curl -XPUT 'localhost:9200/website/blog/123?pretty' -H 'Content-Type: application/json' -d'
{
  "title": "My first blog entry",
  "text":  "I am starting to get the hang of this...",
  "date":  "2014/01/02"
}
'
# 结果中可以看到`_version`字段增加了 1, `created`标志变成了 false
# 在内部,Elasticsearch 已将旧文档标记为已删除,并增加一个全新的文档。尽管你不能再对旧版本的文档进行访问,但它并不会立即消失。当继续索引更多的数据,Elasticsearch 会在后台清理这些已删除文档。

创建新文档

索引一个文档,怎么确认我们正在创建一个完全新的文档,而不是覆盖现有的. _index_type_id 唯一标识一个文档.

curl -XPOST 'http://localhost:9200/website/blog/' -H 'Content-Type: application/json' -d { ... }
  • 通过指定创建方式
# 两种方式
PUT /website/blog/123?op_type=create { ... }
PUT /website/blog/123/_create { ... }
# 建新文档的请求成功,元数据和一个 201 Created
# 相同的 _index 、 _type 和 _id 的文档已经存在 返回 409 Conflict 响应码

删除文档

curl -XDELETE 'localhost:9200/website/blog/123?pretty'
# 找到文档,Elasticsearch 将要返回一个 200 ok 的 HTTP 响应码
# 没有找到文档,我们将得到 404 Not Found 的响应码和类似这样的响应体
# 文档不存在`Found=false`,_version 值仍然会增加。这是 Elasticsearch 内部记录本的一部分,用来确保这些改变在跨多节点时以正确的顺序执行
# 删除文档不会立即将文档从磁盘中删除,只是将文档标记为已删除状态。随着你不断的索引更多的数据,Elasticsearch 将会在后台清理标记为已删除的文档

处理冲突

用 index API 更新文档,可以一次性读取原始文档,做我们的修改,然后重新索引整个文档。 最近的索引请求将获胜:无论最后哪一个文档被索引,都将被唯一存储在 Elasticsearch 中. 有一种会发生冲突的情况, 两个 web 程序并行运行.web _1 对 stock_count 所做的更改已经丢失,因为 web_2 不知道它的 stock_count 的拷贝已经过期。 结果我们会认为有超过商品的实际数量的库存,因为卖给顾客的库存商品并不存在,我们将让他们非常失望

  • 悲观并发控制

这种方法被关系型数据库广泛使用,它假定有变更冲突可能发生,因此阻塞访问资源以防止冲突。一个典型的例子是读取一行数据之前先将其锁住,确保只有放置锁的线程能够对这行数据进行修改

  • 乐观并发控制

Elasticsearch 中使用的这种方法假定冲突是不可能发生的,并且不会阻塞正在尝试的操作。 然而,如果源数据在读写当中被修改,更新将会失败。应用程序接下来将决定该如何解决冲突。 例如,可以重试更新、使用新的数据、或者将相关情况报告给用户

乐观并发控制

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

GETdelete 请求时,我们指出每个文档都有一个 _version 号,当文档被修改时版本号递增。 Elasticsearch 使用这个 _version 号来确保变更以正确顺序得到执行。如果旧版本的文档在新版本之后到达,它可以被简单的忽略

可以利用 _version 号来确保应用中相互冲突的变更不会导致数据丢失。我们通过指定想要修改文档的 _version 号来达到这个目的。如果该版本不是当前版本号,我们的请求将会失败

# 指定了`_create`创建文档
PUT /website/blog/1/_create { ... }
# 获取了文档
GET /website/blog/1
# 指定了`_version=1` 只有当元数据的`_version`字段为 1 的时候才能重新索引 此时的`version`变为 2
PUT /website/blog/1?version=1 { ... }
# 重新运行上面的代码会报错 因为没有 version = 2 的文档了  返回 409 Conflict HTTP 响应码
PUT /website/blog/1?version=1 { ... }

更新或删除 API,都可以接受 version 参数,这允许你在代码中使用乐观的并发控制

文档的部分更新

文档是不可变的:他们不能被修改,只能被替换。 update API 必须遵循同样的规则. 从外部来看,我们在一个文档的某个位置进行部分更新.然而在内部,update API 简单使用与之前描述相同的 检索-修改-重建索引 的处理过程. update 请求最简单的一种形式是接收文档的一部分作为 doc 的参数, 它只是与现有的文档进行合并。对象被合并到一起,覆盖现有的字段,增加新的字段

curl -XPOST 'localhost:9200/website/blog/1/_update?pretty' -H 'Content-Type: application/json' -d'
{
   "doc" : {
      "tags" : [ "testing" ],
      "views": 0
   }
}
'
  • 使用脚本部分更新文档

取回多个文档

加快 Elasticsearch 速度的方式,将多个请求合并成一个,避免单独处理每个请求花费的网络延时和开销.如果你需要从 Elasticsearch 检索很多文档,那么使用 multi-get 或者 mget API 来将这些检索请求放在一个请求中,将比逐个文档请求更快地检索到全部文档

mget API 要求有一个 docs 数组作为参数,每个元素包含需要检索文档的元数据, 包括 _index_type_id 。如果你想检索一个或者多个特定的字段,那么你可以通过 _source 参数来指定这些字段的名字

curl -XGET 'localhost:9200/_mget?pretty' -H 'Content-Type: application/json' -d'
{
   "docs" : [
      {
         "_index" : "website",
         "_type" :  "blog",
         "_id" :    2
      },
      {
         "_index" : "website",
         "_type" :  "pageviews",
         "_id" :    1,
         "_source": "views"
      }
   ]
}
'

代价较小的批量操作

与 mget 可以使我们一次取回多个文档同样的方式, bulk API 允许在单个步骤中进行多次 createindexupdatedelete 请求

# 每行一定要以换行符(\n) 结尾,包括最后一行。这些换行符被用作一个标记,可以有效分隔行
# 这些行不能包含未转义的换行符,因为他们将会对解析造成干扰。这意味着这个 JSON 不 能使用 pretty 参数打印
{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...
  • action/metadata 行指定 哪一个文档做什么操作 。
    • action 必须是以下选项之一:
    • create: 如果文档不存在,那么就创建它。详情请见 创建新文档。
    • index: 创建一个新文档或者替换一个现有的文档。详情请见 索引文档 和 更新整个文档。
    • update: 部分更新一个文档。详情请见 文档的部分更新。
    • delete: 删除一个文档。详情请见 删除文档。
    • metadata: 应该 指定被索引、创建、更新或者删除的文档的 _index 、 _type 和 _id
curl -XPOST 'localhost:9200/_bulk?pretty' -H 'Content-Type: application/json' -d'
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "My first blog post" }
{ "index":  { "_index": "website", "_type": "blog" }}
{ "title":    "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} }
'
  • 请注意 delete 动作不能有请求体,它后面跟着的是另外一个操作
  • 谨记最后一个换行符不要落下
  • 每个子请求都是独立执行,因此某个子请求的失败不会对其他子请求的成功与否造成影响。如果其中任何子请求失败,最顶层的 error 标志被设置为 true ,并且在相应的请求报告出错误明细
  • 这也意味着 bulk 请求不是原子的: 不能用它来实现事务控制。每个请求是单独处理的,因此一个请求的成功或失败不会影响其他的请求
  • bulk 请求的最佳值
    • 整个批量请求都需要由接收到请求的节点加载到内存中,因此该 请求越大 ,其他请求 所能获得的内存就越少 。批量请求的大小有一个最佳值,大于这个值,性能将不再提升, 甚至会下降 。但是最佳值不是一个固定的值。它完全取决于硬件、文档的大小和复杂度、索引和搜索的负载的整体情况
    • 幸运的是,很容易找到这个最佳点 :通过批量索引典型文档,并不断增加批量大小进行尝试。当 性能开始下降 ,那么你的批量大小就 太大 了。一个好的办法是开始时将 1000 到 5000 个文档作为一个批次,如果你的文档非常大,那么就减少批量的文档个数
    • 密切关注你的批量请求的 物理大小 往往非常有用,一千个 1KB 的文档是完全不同于一千个 1MB 文档所占的物理大小。一个好的批量大小在开始处理后所占用的物理大小约为 5-15 MB

分布式文档储存

跳过

聚合

tag: 检索的概念 分布式系统原理 Query DSL 集群内的原理 分布式文档存储 执行分布式检索 分片内部原理

FAQ

  • curl -XGET 'http://127.0.0.1:9200/_count?pretty' -d '{<json>}' 报错 header [application/x-www-form-urlencoded] is not supported 需要加上 -H 'Content-Type: application/json'
  • query 的 match 会对要查询的词进行分词,然后在查找 elasticsearch 查询(match 和 term)
    {
        "query": {
            "match":{
               "eventname":"Microsoft Azure Party"
            }
    }
    // 等同于
    if (doc.eventname contains "microsoft" or doc.eventname contains "azure" or doc.eventname contains "party")
    return doc
    
  • es 对应聚合的值默认返回 top10, 设置不止返回 10 个 es 聚合内容返回更多的值非指定的 top 10
  • es 会把 text 类型以及 string 类型的数据切分, 要精确匹配被分割的值, 要把 term 改成 match_phrase ,或者在字段后面加上关键字 .keyword 参照 es 官网 - 聚合一个指定的字段不切分 , 官方 es 官网 - aggregations and analysis 解释了为什么会出现分词这样的情况
    GET /_index/_type/_search?pertty
    {
        "size": 0,
        "query" : {
            "match_phrase" : {
                "field_name" : "what your want to find"
            }
        }
    }
    // 或者
    GET /_index/_type/_search?pertty
    {
        "size": 0,
        "query" : {
            "match" : {
                "field_name" : "what your want to find"
            }
        }
    }
    
  • es 实现 count(color)
    POST /sales/_search?size=0
    {
        "aggs" : {
            "types_count" : {
                "value_count" : { "field" : "type" }
            }
        }
    }
    
  • es 实现 count(distinct color)
    GET /cars/transactions/_search
    {
        "size" : 0,
        "aggs" : {
            "distinct_colors" : {
                "cardinality" : {
                  "field" : "color"
                }
            }
        }
    }
    
  • es 实现多次查询 es 官网 - Multi Search API
  • es group by 一个指定的字段的时候一般会把字段进行拆分,要避免这种情况就要在 group by 指定为关键字, es 官网 - 聚合一个指定的字段不切分
    GET /bank/_search
    {
      "size": 0,
      "aggs": {
        "group_by_state": {
          "terms": {
            "field": "state.keyword"
          }
        }
      }
    }
    
  • es 聚合的字段默认显示 top 10 如何显示更多, Show all Elasticsearch aggregation results/buckets and not just 10
    GET /bank/_search
    {
      "size": 0,
      "aggs": {
        "group_by_state": {
          "terms": {
            "field": "state.keyword",
            // you have to use explicitly number in here
            "size": 10000000
          }
        }
      }
    }
    
  • es 要匹配同一个字段的多个值 termses 官网 - Finding Multiple Exact Values
    {
      "terms" : {
          "price" : [20, 30]
      }
    }
    
  • 查询指定中心点和半径的地理信息 es 官网 - geo 图形查询
    GET /attractions/landmark/_search
    {
      "query": {
        "geo_shape": {
          "location": {
            "shape": {
              "type":   "circle",
              "radius": "1km",
              "coordinates": [
                4.89994,
                52.37815
              ]
            }
          }
        }
      }
    }
    
  • 获取字段前面的值
    GET /_search
    { "query": {
        "prefix" : { "user" : "ki" }
      }
    }
    

ES VS Mongodb

Ref

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

似梦非梦

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

lee_heart

文章 0 评论 0

往事如风

文章 0 评论 0

春风十里

文章 0 评论 0

纸短情长

文章 0 评论 0

qq_pdEUFz

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文