dream

一个菜鸟程序员的成长历程

0%

URI Search

通过URI query 实现搜索

参数:

  • q:指定查询语句,使用Query String Syntax
  • df:默认字段,不指定会对所有字段进行查询
  • sort:排序
  • from/size: 用来分页
  • Profile 可以查看查询是如何被执行的

Query String Syntax

指定字段和泛查询

泛查询

q参数后面只跟着查询内容会对所有字段进行搜索,可以看到返回值里面profile-query-typeDisjunctionMaxQuerydescription(customer_name.keyword:产品 | (job_name:产 job_name:品) | job_name.keyword:产品 | (customer_name:产 customer_name:品) | MatchNoDocsQuery("failed [id] query, caused by number_format_exception:[For input string: "产品"]") | (city_names:产 city_names:品) | city_names.keyword:产品)

指令

1
2
3
4
GET test_home/_search?q=产品
{
"profile": "true"
}

指定字段

指定字段有两种方式,一种是df参数

指令

1
2
3
4
GET test_home/_search?q=产品&df=job_name
{
"profile": "true"
}

还有一种是q参数使用冒号来分隔

指令

1
2
3
4
GET test_home/_search?q=job_name:产品
{
"profile": "true"
}

指定字段的返回参数可以看到typeBooleanQuery,descriptionjob_name:产 job_name:品

term query & PhraseQuery

term query 是 or的关系,比如上面搜索产品,只要包含或者就都会搜索出来,可以用()小括号把搜索内容括起来

phrase query 是 and 的关系,需要再搜索内容上加双引号。这样只会搜索出产品的结果。

指令

1
2
3
4
GET test_home/_search?q=job_name:"产品"
{
"profile": "true"
}

boolean query

boolean query可以用AND,OR,NOT来操作
比如既要又要
指令

1
2
3
4
GET test_home/_search?q=job_name:(产 AND 品)
{
"profile": "true"
}

比如只有一个就行
指令

1
2
3
4
GET test_home/_search?q=job_name:(产 OR 品)
{
"profile": "true"
}

比如只有品没有产

指令

1
2
3
4
GET test_home/_search?q=job_name:(品 NOT 产)
{
"profile": "true"
}

范围查询

区间表示 []闭区间 {}开区间

  • year:[2019 TO 2.18]

算术符号

可以使用>,<,=等数学符号

通配符查询

通配符查询效率低,占用内存大,不建议使用。

正则表达式

可以用正则进行匹配搜索查询

  • job_name:[bt]oy

模糊匹配与近似查询

模糊查询允许用户输错查询关键字

比如上面的查询产品,用户打错了,输成了品阶。我们通过模糊匹配依旧可以查询出来内容.就是通过在查询内容后面输入~1代表允许1个字的错误

指令

1
2
3
4
GET test_home/_search?q=job_name:品阶~1
{
"profile": "true"
}

极客时间 ES 学习笔记

query string和simple query string

query string

类似URI query

指令

1
2
3
4
5
6
7
8
9
POST users/_search
{
"query":{
"query_string":{
"default_field":"job_name", //相当于URI的 df
"query":"产品"
}
}
}

还可以搜索多个字段

指令

1
2
3
4
5
6
7
8
9
POST users/_search
{
"query":{
"query_string":{
"query":"产品",
"fields":['job_name'] //搜索job_name是产品的
}
}
}

还可以直接在query里面使用AND,OR,NOT的操作符

指令

1
2
3
4
5
6
7
8
9
10
POST users/_search
{
"query":{
"query_string":{
"query":"产 OR 品",
"fields":['job_name'] //搜索job_name是产品的
}
}
}

simple query string

类似 query string ,但是会忽略错误的语法,同时只支持部分查询语法

  • 不支持AND OR NOT ,会当做字符处理
  • Term 之间默认的关系是OR,可以指定 operator
  • 支持 部分逻辑
    • +代替AND
    • |代替OR
    • -代替NOT

这里如果使用了+或者AND还有OR,那么会使用AND,而OR不生效。

指令

1
2
3
4
5
6
7
8
9
10
POST users/_search
{
"query":{
"query_string":{
"query":"产-品", //这里-代表OR
"fields":['job_name'] //搜索job_name是产品的
"default_operator": "OR" //指定默认操作符
}
}
}

极客时间 ES 学习笔记

正排索引和倒排索引

正排索引

正排索引就是通过索引id找到内容,比如通过书本的目录找到内容。

倒排索引

倒排索引就是把正排索引倒过来,通过内容找到索引id.

建立一个倒排索引

id 内容
1 php java go
2 php es
3 php 开发

把上面的内容可以建立成下面的倒排索引

内容 Count id
php 3 1:0,2:0,3:0
java 1 1:1
go 1 1:2
es 1 2:1
开发 1 3:1

倒排索引的核心组成

单词词典 记录所有文档的单词 记录单词到倒排列表的关联关系。
单词词典一般比较大,可以通过B+树或hash拉链法实现,以满足高性能的插入和查询

倒排列表记录了单词对应的文档结合,由倒排索引项组成

倒排索引项

  • 文档id
  • 词频 该单词在文档中出现的次数,用于相关性评分
  • 位置 单词在文档中分词的位置。用于语句搜索
  • 偏移 记录单词的开始结束位置,实现高亮显示

ES中的倒排索引

ES的JSON文档中的每个字段,都有自己的倒排索引
可以指定对某些字段不做索引

  • 优点:节省存储空间
  • 缺点:字段无法被搜索

极客时间 ES 学习笔记

显式mapping

设置mapping

指令

1
2
3
4
5
6
7
8
9
10
PUT {index}
{
"mappings":{
"properties":{ //设置mapping
"job_name":{
"type":"text"
}
}
}
}

自定义Mapping

可以参考 API 手册,纯手写

也可以复制现有的动态Mapping:

  • 创建一个临时的index,写入一些样本数据
  • 通过访问 Mapping API 获得该临时文件的动态 Mapping 定义
  • 修改后,使用该配置创建你的索引
  • 删除临时索引

index

index 控制当前字段是否被索引。默认为true,如果设置成false,就不会被索引,不能被搜索。

优点:不会建立倒排索引,更节省内存空间
缺点:该字段不能被搜索

指令

1
2
3
4
5
6
7
8
9
10
11
PUT {index}
{
"mappings":{
"properties":{ //设置mapping
"job_name":{
"type":"text",
"index":false //这里设置false,这个字段就不能被搜索
}
}
}
}

index options

有四种不同级别的 index options 配置,可以控制倒排索引记录的内容

  • docs - 记录 doc id
  • freqs - 记录 doc id 和 term frequencies
  • positions - 记录 doc id / term frequencies / term position
  • offsets - 记录 doc id / term frequencies / term position / character offects

Text类型默认记录 positions ,其他默认为 docs

记录内容越多,占用存储空间越大。

指令

1
2
3
4
5
6
7
8
9
10
11
PUT {index}
{
"mappings":{
"properties":{ //设置mapping
"job_name":{
"type":"text",
"index_options":"offsets" //这里设置index_options
}
}
}
}

null value

如果需要对 NULL 值进行搜搜,那么只有 Keyword 类型支持设定 null_value

指令

1
2
3
4
5
6
7
8
9
10
11
PUT {index}
{
"mappings":{
"properties":{ //设置mapping
"job_name":{
"type":"text",
"null_value":"NULL" //这里设置null_value
}
}
}
}

copy_to

copy_to 相当于以前的 _all 。可以满足一些特定的搜索需求。copy_to 将字段的数值拷贝到目标字段,实现类似_all的作用。copy_to的目标字段不会出现在_source中

指令

1
2
3
4
5
6
7
8
9
10
11
PUT {index}
{
"mappings":{
"properties":{ //设置mapping
"job_name":{
"type":"text",
"copy_to":"fullName" //这里设置copy_to
}
}
}
}

数组类型

ES不提供专门的数组类型。但是任何字段,都可以包含多个相同类型的数值。

指令

1
2
3
4
5
6
7
PUT test_home/_doc/1
{
"job_name":"php",
"city":[
"北京市","上海市"
]
}

可以看到 city 就是一个数组。但是如果查看 mapping 会发现 city 是一个 text/Keyword 类型。

极客时间 ES 学习笔记

基本操作

文档的CRUD

  • Create 如果id 已经存在,会失败
  • Index 如果id不存在,创建新的文档。否则先删除在创建新的,版本会增加
  • Update 文档必须已经存在,更新只会对相应字段做增量修改

Create

指令

1
2
3
4
5
6
7
8
9
10
PUT {index}/_doc/{id}?op_type=create  //只是创建
{JSON}

PUT {index}/_doc/{id} //创建或更新
{JSON}

PUT {index}/_create/{id} //只是创建
{JSON}

POST {index}/_doc/ //只是创建 自动生成id
  • 如果通过op_type参数指定create那么就只会创建,如果存在会报错
  • 支持自动生成文档ID,和指定ID两种方式
  • 通过调用 POST /index/_doc.不指定ID系统就会自动生成
  • 使用 HTTP PUT index/_create/1 创建,URI中显式指定 _create,如果该ID的文档已经存在,则操作失败。

ES

GET

指令

1
GET {index}/{type}/{id} index/_doc/1

找到文档。HTTP 200,找不到就返回 404

元信息

  • _index/_type
  • 版本信息,同一个ID的文档,即使被删除,Version也会不断增加
  • _source 中默认包含了文档的所有原始信息

ES

Index

指令

1
2
PUT {index}/{type}/{id} index/_doc/1
{JSON}

Index和Create不一样的地方就在于存在就删除在创建,并且版本号增加。

Update

Update 是直接更新

指令

1
2
3
4
POST {index}/_update/{id}
{
"doc":{JSON}
}

ES

Delete

Delete是删除操作

指令

1
DELETE {index}/_doc/{id}

批量操作 Bulk API

支持一次调用,对不同的索引进行操作
支持

  • Index
  • Create
  • Update
  • Delete

只有一次网络请求,单条失败不会影响其他操作结果

返回结果包括每一条的执行结果

指令

1
2
3
4
5
6
7
8
POST _bulk
{ "index":{"_index":"test", "_id":"1"} } //指定index和_id
{ "field1":"value1" } //index 的数据
{ "delete" : {"_index":"test" "_id":"2"}} //delete 的 index 和id
{ "create": {"_index":"test2","_id":1}} //create 的index id
{ "field1":"value3"} //create 的数据
{ "update":{"_id":1,"_index":"test"}} //update 的id index
{ "doc":{"field2":"value2"}} //update 的数据

ES

批量获取 mget

批量操作,可减少网络开销

指令

1
2
3
4
5
6
7
8
9
POST _mget
{
"docs":[
{
"_index":"user"
"_id":1
}
]
}

ES

批量查询 msearch

指令

1
2
3
4
5
POST {index}/_msearch
{} //注意这里需要加上这个 不加会报错
{"query": {"match_all":{}},"size":1}
{"index": user }
{"query": {"match_all":{}},"size":1}

ES

常见错误返回

问题 原因
无法连接 网络故障或集群挂了
连接无法关闭 网络故障或节点出错
429 集群过于繁忙
4xx 请求体格式有错
500 集群内部错误

极客时间 ES 学习笔记

基本概念

分布式系统的可用性与扩展性

高可用性

  • 服务可用性:允许有节点停止服务。
  • 数据可用性:部分节点丢失,不会丢失数据。

可扩展性

  • 请求量提升/数据的不断增长(将数据分布到所有节点上)

分布式特性

Elasticsearch 的分布式架构好处

  • 存储的水平扩容
  • 提高系统的可用性,部分节点停止服务,整个集群的服务不受影响

Elasticsearch的分布式架构

  • 不同的集群通过不同的名字来区分,默认名字“Elasticsearch”
  • 通过配置文件修改,或者在命令行中 -E cluster.name=xxx来设置
  • 一个集群可以有一个或多个节点

节点

节点是一个Elasticsearch 的实例

  • 本质上就是一个JAVA进程
  • 一台机器上可以运行多个Elasticsearch进程,但是线上建议一个机器一个节点

每一个节点都有名字,通过配置文件配置,或者启动时 -E node.name=xxx 来设置

每个节点在启动之后会有一个UID,保存在data目录下

Master-eligible nodes 和 Master Node

每个节点启动后,默认是一个 Master eligible 节点。

  • 可以设置 node.master:false 禁止
    Master-eligible 节点可以参加选主流程,成为 master 节点

当第一个节点启动时候,它会将自己选举成为 master 节点

每个节点上都保存了集群的状态,只有 master 节点才能修改。

  • 集群状态(Cluster State),维护了一个集群中必要的信息
    • 所有的节点信息
    • 所有的索引和其相关的 Mapping 与 Settings 信息
    • 分片的路由信息
  • 任意节点都可以修改会导致数据的不一致

Data Node 和 Coordinating Node

Data Node

  • 可以保存数据的节点,叫做Data Node。 负责保存分片数据。在数据扩展上起到了至关重要的作用。

Coordinating Node

  • 负责接受Client 的请求,将请求分发到合适的节点,最终把结果汇集到一起。
  • 每个节点默认都起到了Coordinating Node的职责

其他的节点类型

Hot & Warm Node

  • 不同硬件配置的Data Node ,用来实现 Hot & Warm 架构,降低集群部署的成本。

Machine Learning Node

  • 负责跑机器学习的Job,用来做异常检测

Tribe Node

  • (5.3开始使用 Cross Cluster Search) Tribe Node 连接到不同的Elasticsearch 集群,并且支持将这些集群当成一个单独的集群处理

配置节点类型

生产环境建议一个节点担任一个角色

节点类型 配置参数 默认值
maste eligible node.master true
data node.data true
ingest node.ingest true
coordinating only 每个节点默认都是coordinating节点,设置其他类型全部为false
machine learning node.ml true(需要 enable x-pack)

分片(Primary Shard & Replica Shard)

主分片,用以解决数据水平扩展的问题。通过主分片,可以将数据分布到集群内的所有节点之上。

  • 一个分片是一个运行的Lucene的实例
  • 主分片数在索引创建时指定,后续不允许修改,除非Reindex

副本,用以解决数据高可用的问题。分片是主分片的拷贝

  • 副本分片数,可以动态调整
  • 增加副本数,还可以在一定程度上提高服务的可用性(读取的吞吐)

分片的设定

对于生产环境,需要提前做好容量规划

分片数设置过小

  • 导致后续无法增加节点实现水平扩展
  • 单个分片的数据量太大,导致数据重新分配耗时

分片数设置过大,7.0开始,默认分片设置为1,解决了over-sharding的问题

  • 影响搜索结果的相关性打分,影响统计结果的准确性
  • 单个节点上过多的分片,会导致资源浪费,同时也会影响性能

查询集群的健康状态

使用GET方法访问 _cluster/health

1
GET /_cluster/health

或者访问 http://localhost:9200/_cluster/health

Green : 集群健康
Yello : 主分片分配,副本未分配
Red : 主分片未分配

基本概念

文档(Document)

Elasticsearch 是面向文档的,文档是所有可搜索数据的最小单位。

  • 日志文件中的日志项。
  • 电影的具体信息/唱片的具体信息
  • MP3播放器里的一首歌/一篇PDF文档中的具体内容

文档会被序列化成 JSON 格式,保存在Elasticsearch中。

  • JSON对象由字段组成
  • 每个字段都有对应的字段类型(字符串/数值/布尔/日期/二进制/范围类型)

每个文档都有一个Unique ID

  • 你可以自己指定ID
  • 或者通过Elasticsearch自己生成

文档的元数据

  • 元数据,用于标注文档的相关信息
    • _index - 文档所属的索引名
    • _type - 文档所属的类型名
    • _id - 文档唯一的ID
    • _source - 文档的原始JSON数据
    • _all - 整合所有字段内容到该字段,已被废除
    • _version - 文档的版本信息
    • _score - 相关性打分

索引(Index)

索引文档的容器,是一类文档的集合。

  • Index 体现了逻辑空间的概念:每个索引都有自己的Mapping定义,用于定义包含的文档的字段名和字段类型
  • Shard 体现了物理空间的概念:索引中的数据分散在Shard上

索引的 Mapping 和 Settings

  • Mapping 定义文档字段的类型
  • Setting 定义不同的数据分布

索引的不同语意

  • 名词:一个Elasticsearch中,有多个不同的索引。
  • 动词:保存一个文档到Elasticsearch的过程也叫索引(indexing)
    • ES中,创建一个倒排索引的过程
  • 名词:一个B树索引,一个倒排索引

类型Type

  • 7.0 开始 每个索引只能 创建一个 Type - “_doc”

REST API

Elasticsearch提供了REST API的方式进行调用,这样不管什么语言都可以通过HTTP的方式进行调用。

这些API的文档可以在Elasticsearch的文档里面找到.

可以在Kibana里面的dev tools进行REST API的测试。

ES–安装

安装

  • 运行ElasticSearch, 需安装并配置JDK

    • 设置 $JAVA_HOME
  • 各个版本对 Java的依赖

从官网(https://www.elastic.co/cn/downloads/elasticsearch)可以进行下载安装

目录说明

  • bin : 脚本文件,包括启动 ElasticSearch,安装插件。运行统计数据等。
  • config : 配置文件:elasticsearch.yml。集群配置文件,user,role based相关配置
  • JDK: Java运行环境
  • data: path.data 数据文件
  • lib : Java类库
  • logs: path.log 日志文件
  • modules: 包含所有ES模块
  • plugins: 包含所有已安装插件

JVM配置

启动

单节点启动

1
/bin/elasticsearch

启动后可以访问 localhost:9200 进行查看信息

多节点启动

cluster.name 指定同一个集群,node.name指定每个节点的名称,path.data指定数据存放位置

1
2
3
/bin/elasticsearch -E node.name=node1 -E cluster.name=test -E path.data=node1_data -d
/bin/elasticsearch -E node.name=node2 -E cluster.name=test -E path.data=node2_data -d
/bin/elasticsearch -E node.name=node3 -E cluster.name=test -E path.data=node3_data -d

启动完成以后可以直接访问localhost:9200/_cat/nodes查看node信息

安装插件

使用elasticsearch-plugin进行插件的安装和查看

1
2
/bin/elasticsearch-plugin list   //查询已安装的插件列表
/bin/elasticsearch-plugin install analysis-icu //安装analysis-icu插件

还可以通过api进行查看已安装的插件,访问localhost:9200/_cat/plugins可以查看已安装的插件

ES–简介

起源

ES起源于Lucene.Lucene是基于JAVA开发的搜索引擎类库。

Lucene具有高性能,易扩展的优点。

Lucene的局限性:

  1. 只能基于JAVA开发
  2. 类库的接口学习曲线陡峭
  3. 原生并不支持水平扩展

ES的诞生

ES的创始人Shay Banon说过:Search is something that any application should have

2004年基于Lucene开发了 Compass

2010年重写了 Compass ,取名 ElasticSearch

  • 支持分布式,可水平扩展
  • 降低全文检索的学习曲线,可以被任何编程语言调用

ES的分布式架构

集群规模可以从单个扩展至数百个节点

高可用 & 水平扩展
- 服务和数据两个维度

支持不同的节点类型
- 支持 Hot & Warm架构

主要功能

  • 海量数据的分布式存储以及集群管理

    • 服务与数据的高可用,水平扩展
  • 近实时搜索,性能卓越

    • 结构化/全文/地理位置/自动完成
  • 海量数据的近实时分析

    • 聚合功能

新特性5.x

  • Lucene 6.x ,性能提升,默认打分机制从TF-IDF改为BM25
  • 支持Ingest节点/ Painless Scripting / Completion suggested 支持/ 原生的JAVA REST客户端
  • Type 标记成 deprecated ,支持了keyword类型
  • 性能优化
    • 内部引擎移除了避免同一文档并发更新的竞争锁,带来15 - 20%的性能提升
    • Instant aggregation,支持分片上聚合的缓存
    • 新增了Profile API

新特性6.x

  • Lucene 7.x
  • 新功能
    • 跨集群复制(CCR)
    • 索引生命周期管理
    • SQL的支持
  • 更友好的升级及数据迁移
    • 在主要版本之间的迁移更为简化,体验升级
    • 全新的基于操作的数据复制框架,可加快回复数据。
  • 性能优化
    • 有效存储稀疏字段的新方法,降低了存储成本
    • 在索引时进行排序,可加快排序的查询性能

新特性7.x

  • Lucene 8.x
  • 重大改进 - 正式废除单个索引下多Type的支持
  • 7.1开始,Security功能免费使用
  • ECK - ElasticSearch Operator on Kubernetes
  • 新功能
    • New Cluster coordination
    • Feature-Complete High Level Rest Client
    • Script Score Query
  • 性能优化
    • 默认的Primary Shard 数从5变为1,避免Over Sharding
    • 性能优化,更快的Top K