一、elasticsearch介绍

1、背景

在订单管理系统中,订单查问的调用量都十分大,如果间接查询数据库,那数据库的压力可想而知,而且有时须要执行一些简单的查问,sql 并不可能敌对的反对,须要查问很多张表。再比方用户手误输出的关键词错了或存在错别字,那应用 sql 是无奈搜寻到。所以打算应用 Elasticsearch 来承载订单查问的次要压力。

总的来说,应用 elasticsearch,以下简称es 的几个起因如下

  • 关系型数据库在进行含糊(%关键字%)搜寻的时候,会全表扫描,查问十分慢
  • 关系型数据库在关键字搜寻时,并不反对全文分词搜寻,比方用户本打算搜寻:公众号-臻大虾,却手误:公号-臻大虾,es 能够依据分词的后果搜寻出想要的后果。
  • 在数据分析、日志剖析上用到 es

2、es 基本概念

Elasticsearch 是一个分布式、RESTful 格调的搜寻和数据分析引擎,实用于包含文本、数字、天文空间、结构化和非结构化数据等在内的所有类型的数据。Elasticsearch 在 Apache Lucene 的根底上开发而成,由 Elasticsearch N.V.(即当初的 Elastic)于 2010 年首次公布。

Elasticsearch 是文件存储,Elasticsearch 是面向文档型数据库,一条数据在这里就是一个文档,用 JSON 作为文档序列化的格局,比方上面这条用户数据:

{    "name":"臻大虾",    "sex":0,    "age":24}

3、es 劣势

  • 分布式:横向可扩展性,减少服务器可间接配置在集群中
  • 高可用:提供了复制性能,具备容错机制,能主动发现新的或失败的节点,重组和从新均衡节点数据
  • 实时性:数据进入 es,可达到近实时搜寻
  • Restful api:json 格局的 RESTful 格调
  • 全文检索:基于 lucene 的弱小的全文检索能力

4、应用场景

全文检索

当咱们应用百度搜寻、谷歌搜寻时,输出关键字,就能搜寻到最相干的文章,这就是利用了 es 弱小的全文检索的能力。

用户行为

平时淘宝买货色时,你是否发现举荐的商品跟你最近搜寻的关键词很享受,这就是通过收集用户的行为日志,剖析并建设用户模型,保留在 es 中,并利用 es 弱小的深刻搜寻和聚合的能力,能够更好的剖析和展现用户的行为数据。例如举荐零碎,就是利用用户模型的用户数据,对用户数据穿插查问,剖析出用户细粒度的爱好。

监控零碎

利用 es 高性能查问的个性,收集零碎的监控数据,近实时展示监控数据,同时也不便用户对监控数据进行关键字排查。

日志零碎

罕用的计划是 ELK(elasticsearch+logstash+kibana),利用 logstash 去收集 logback 的日志信息,再通过 es 做存储,最初能够再 kibana 去利用 es api 查看和剖析日志的相干信息。

5、es 的外围概念

索引(index)

索引是 es 最大的数据单元,相似于关系型数据库中的库,是多个类似文档的汇合。每个索引有一个或多个分片,每个分片有多个副片。

文档(document)

一条数据就是一个文档,相似于数据库表中的一条记录,比方:

{    "name":"臻大虾",    "sex":0,    "age":24}

字段(field)

文档的属性,相似表中的字段,比方如下 json 的健:name

{    "name":"臻大虾"}

映射(mapping)

映射是对文档中每个字段类型进行定义,相似表构造,蕴含数据类型,长度之类的,比方:

"mappings": {        "properties": {            "name": {                "type": "text"            },            "age": {                "type": "long"            }        }    }

分片(Shards)

在创立索引时,能够设置主分片个数和正本个数,相似数据库的分表,将单个索引文件分成多份存储,当申请过去时,通过路由计算找到主分片(hash(字段,比方 id)%分主片数量)。

益处:

  • 如果一个索引数据量很大,会造成硬盘和搜寻速度的瓶颈,分片能分担压力
  • 分片容许咱们进行程度切分和扩大容量
  • 能够在多个分片上进行分布式的、并行的操作,进步零碎吞吐量
留神:主分片在创立之后是无奈批改的,而正本能够随时批改。那想批改主分片的数量怎么办呢,删除从新建。
"settings": {    "number_of_shards": 2,//主分片    "number_of_replicas": 1//正本}

正本(Replicas)

由主分片复制来的,提供高可用

益处:

  • 高可用,当一个主分片挂了,正本能够代替工作
  • 正本也能够执行搜寻操作,摊派了主分片的压力

集群(Cluster)

一个集群就是由一个或多个节点组织在一起,具备雷同集群名的节点能力组成一个集群。它们独特持有整个的数据,并一起提供索引和搜寻性能。

留神:主分片和正本处于不同节点,这样当主分片的机器挂了,正本因为在不同机器上,不会受到影响,正本变为主分片持续工作。所以 es 最小的高可用配置为两台服务器

节点(node)

单个 es 实例称为一个节点(node),一个节点是集群中的一个服务器,作为集群的一部分,存储数据。

类型(type)

7.x 移除了 type,8.x 将彻底移出

image-20210920183804825

二、索引原理

es 应用的是倒排索引也叫反向索引,既然有倒排索引,那是不是有正排索引,有的,咱们先介绍下正排索引。

1、正排索引

正排索引是以文档的 ID 为关键字,文档中每个字段的值为 value,次要场景是通过 id 获取文档信息,平时用的 msyql 关系型数据库就是以这种形式查问的。

举个例子

id内容
1my name is zhendaxia
2my name is jack

通过 id 能够很快查问到内容,然而当查问比方 name 的时候,须要应用 like,再加上数据量大的时候,查问的工夫是很久的,无奈满足查问疾速的要求。

2、倒排索引

倒排索引是以字或词为关键字进行索引,记录呈现这个关键词的文档的 ID

比方下面的例子应用倒排索引如下:

contentdocid
my1,2
name1,2
is1,2
zhendaxia1
jack2

倒排索引,通过字或词疾速的找到所有文档的 id,在依据文档 id 能疾速找到内容。因为人类的词汇数量是绝对无限且固定的,所以效率并不会因为日后关键词的增长而受到很大的影响。

三、集群扩容

1、集群衰弱

image-20210920221154778

集群的衰弱状态有三种:绿色 green、黄色 yellow、红色 red

绿色(衰弱):所有的主分片和副分片都失常运行

黄色(亚健康):所有主分片失常运行,但有副分片没失常运行

红色(不衰弱):有主分片没失常运行

2、扩容

扩容个别分为两种,垂直和程度

1)、垂直扩容

降级服务器,买性能更好的服务器替换原有的服务器,不过这种扩容不举荐,毕竟单台机器的性能总是有瓶颈的

2)、程度扩容

程度扩容也叫横向扩容,就是减少服务器数量,多台一般的服务器组织在一起造成弱小的计算能力。俗话说:团结就是力量。

四、浏览器插件

head 插件是 ES 的一个可视化插件,相似于 navicat 和 mysql 的关系。head 插件是一个用来浏览、与 ES 数据进行交互的 web 前端展现插件,是一个用来监督 ES 状态的客户端插件。

以下是插件的一些简略介绍

image-20210920225224119

五、罕用 api

1、创立索引

PUT /index{    "settings": {        "number_of_shards": 2,        "number_of_replicas": 1    },    "mappings": {        "properties": {            "text_name": {                "type": "text"            },            "keyword_name": {                "type": "keyword"            },            "english_name": {                "type": "text",                "fields": {                    "keyword": {                        "type": "keyword"                    }                }            },            "age": {                "type": "long"            },            "classId": {                "type": "long"            },            "score": {                "type": "long"            },            "createTime": {                "type": "long"            }        }    }}

当看到申请体时,仔细的你可能会发现 text\_name、keyword\_name、english\_name 这三个字段都是字符串,但类型如同有些不同,区别是什么呢?是的,这几个类型往往是刚接触 es 的老手常常弄错的中央。

首先,看下 text 和 keyword 的区别

text:能够分词,用户全文搜寻,能够含糊匹配搜寻

keyword:不能分词,关键词搜寻,只能对某个值进行整体搜寻

type 是 text,但有 fields-keyword:这种类型,一种是本人退出的,另一种是在往 es 插入数据的时候,字段 english\_name 还没有创立。

这时 es 会依据数据类型,主动帮你创立一个字段,如果是字符串类型,因为无奈判断你的这个字符串你是用来准确查问还是含糊查问,所以 es 会创立类型是 text,反对含糊查问,同时会创立 fields,type 是 keyword,反对准确查问,所以当你要准确查问的时候,字段名就不是原来的 english\_name,而是要应用 english\_name.keyword

举个例子来阐明下,首先插入了以下数据,关键字 zhen

{    "text_name": "zhen daxia",    "keyword_name": "zhen daxia",    "english_name": "zhen daxia",    "age": 18,    "classId": 2,    "score": 90,    "createTime": 1629353892784}
  • 查问 text\_name,因为 text\_name 类型是 text,会讲 zhen daxia 分词为 zhen、daxia,所以当应用 zhen 查问时,能匹配到 zhen,所以会有后果返回.
如何查看 zhen daxia 被分为哪些词语,能够应用 GET 你的索引/\_doc/数据 id/\_termvectors?fields=字段名,比方我的索引是 test-user,那语句就是:GET test-user/\_doc/1/\_termvectors?fields=text\_name
GET test-user/_search{  "query": {   "term": {     "text_name": {       "value": "zhen"     }   }  }}

image-20210920232241959

  • 查问 keyword\_name,因为 keyword\_name 类型是 keyword,不会分词,所以 zhen 无奈搜寻到数据

image-20210920232950219

  • 查问 english\_name,同 text\_name,能够搜到

image-20210920233814208

  • 查问 english\_name.keyword,同 keyword\_name,无奈搜寻到后果

image-20210920233927960

2、减少映射字段

PUT /index/_mapping{    "properties":{        "keyword-name":{            "type":"keyword"        }    }}

3、查问

GET test-user/_search

3.1 match(全文检索)

全文检索,会分词,含糊查问,比方关键字 zhen daxia,会被拆为 zhen、daxia

{  "query": {    "match": {      "text_name": "zhen daxia"    }  }}

spring boot 办法

boolQueryBuilder.filter(QueryBuilders.matchQuery("text_name", "zhen daxia"));

3.2 term(准确查问)

准确查问,不会拆词,比方关键字 zhen daxia,会间接应用 zhen daxia 搜寻

{  "query": {    "term": {      "keyword_name": {        "value": "zhen daxia"      }    }  }}

spring boot 办法

QueryBuilders.termQuery("keyword_name", "zhen daxia");

3.3 terms(多值匹配)

和 term 查问一样,但它容许你指定多值进行匹配,如果这个字段蕴含了指定值中的任何一个值,那么这个文档就算是满足条件。相似 mysql 的 in

{  "query": {   "terms": {     "keyword_name": [       "zhen",       "daxia"     ]   }  }}

spring boot 办法

QueryBuilders.termsQuery("keyword_name", Lists.newArrayList("zhen","daxia"));

3.4 range(范畴查问)

范畴查问,比方搜寻大于等于 20 且小于等于 30 的数据

{  "query": {    "range": {      "age": {        "gte": 20,   # 大于等于  大于用 gt        "lte": 30    # 小于等于  小于用 lt      }    }  }}

spring boot 办法

RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age");rangeQueryBuilder.gte(20);rangeQueryBuilder.lte(30);

3.5 prefix(前缀查问)

前缀查问,比方搜寻 zhen,则前缀是 zhen 的都会被搜寻进去

{  "query": {    "prefix": {      "keyword_name": {        "value": "zhen"      }    }  }}

spring boot 办法

QueryBuilders.prefixQuery("keyword_name","zhen");

3.6 wildcard(通配符含糊查问)

通配符含糊查问,相似 mysql 的 like,?匹配一个字符,*匹配 0~n 个字符

{  "query": {    "wildcard": {      "keyword_name": {        "value": "*大虾"      }    }  }}

spring boot 办法

QueryBuilders.wildcardQuery("keyword_name","*大虾")

3.7 fuzzy(含糊查问,不准确查问)

不同于 mysql 的 like,它能够谬误一些字,比方搜寻 mock,能够搜寻出 mick

{  "query": {    "fuzzy": {      "keyword_name": "mock"    }  }}

spring boot 办法

QueryBuilders.fuzzyQuery("keyword_name","mock");

3.8 must、must not、should

//must:必须boolQueryBuilder.must(QueryBuilders.termQuery("keyword_name","mick"));//must not:非boolQueryBuilder.mustNot(QueryBuilders.termQuery("keyword_name","mick"));//should:相似mysql的或boolQueryBuilder.should(QueryBuilders.termQuery("keyword_name","jack"));boolQueryBuilder.should(QueryBuilders.termQuery("keyword_name","mick"));

3.9 match all(查问全副)

查问全副,默认 10 条

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();sourceBuilder.query(matchAllQueryBuilder);sourceBuilder.size(10);

3.10 match\_phrase

  • 分词后,待查问的字段同时匹配分词后的所有关键词
  • 程序也是一样

比方有以下数据:

1. keyword_name:zhen daxia2. keyword_name:daxia zhen3. keyword_name:I am zhen daxia4. keyword_name:daxia haha

查问 zhen daxia,则返回 1 和 3,2:程序不对,4:没有匹配到全副分词

可通过 slp 调节因子,比方 1,少匹配一个也满足

{  "query": {    "match_phrase": {     "keyword_name": {       "query": "zhen daxia",       "slop": 1     }    }  }}

3.11 multi\_match(多字段匹配)

多字段匹配,有一个字段匹配,就满足,keyword\_name=jack,或 english\_name=jack,就算满足

{  "query": {   "multi_match": {     "query": "jack",     "fields": ["keyword_name","english_name"]   }  }}j

3.12 filter 和 must(过滤)

filter 与 must 是属于同一个级别的查问形式,都能够作为 query->bool 的属性 filter:不计算评分, 查问效率高;有缓存(举荐) must:要计算评分,查问效率低;无缓存

3.13 聚合查问(聚合)

依据名字分组

builder.aggregation(AggregationBuilders.terms("agg").field("keyword_name").size(10));

关注公众号:臻大虾,分享更多java后端干货

你的反对是对我一直创作的极大激励,咱们下期见。