全文检索elasticsearch入门,看这篇就够了

全文检索elasticsearch入门,看这篇就够了
文章图片

1、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)
由主分片复制来的,提供高可用
好处:
  • 高可用,当一个主分片挂了,副本可以代替工作
  • 副本也可以执行搜索操作,分摊了主分片的压力
【全文检索elasticsearch入门,看这篇就够了】集群(Cluster)
一个集群就是由一个或多个节点组织在一起,具有相同集群名的节点才能组成一个集群。它们共同持有整个的数据,并一起提供索引和搜索功能。
注意:主分片和副本处于不同节点,这样当主分片的机器挂了,副本由于在不同机器上,不会受到影响,副本变为主分片继续工作。所以 es 最小的高可用配置为两台服务器
节点(node)
单个 es 实例称为一个节点(node),一个节点是集群中的一个服务器,作为集群的一部分,存储数据。
类型(type)
7.x 移除了 type,8.x 将彻底移出
全文检索elasticsearch入门,看这篇就够了
文章图片

image-20210920183804825
二、索引原理 es 使用的是倒排索引也叫反向索引,既然有倒排索引,那是不是有正排索引,有的,我们先介绍下正排索引。
1、正排索引 正排索引是以文档的 ID 为关键字,文档中每个字段的值为 value,主要场景是通过 id 获取文档信息,平时用的 msyql 关系型数据库就是以这种方式查询的。
举个例子
id 内容
1 my name is zhendaxia
2 my name is jack
通过 id 可以很快查询到内容,但是当查询比如 name 的时候,需要使用 like,再加上数据量大的时候,查询的时间是很久的,无法满足查询快速的要求。
2、倒排索引 倒排索引是以字或词为关键字进行索引,记录出现这个关键词的文档的 ID
比如上面的例子使用倒排索引如下:
content docid
my 1,2
name 1,2
is 1,2
zhendaxia 1
jack 2
倒排索引,通过字或词快速的找到所有文档的 id,在根据文档 id 能快速找到内容。由于人类的词汇数量是相对有限且固定的,所以效率并不会由于日后关键词的增长而受到很大的影响。
三、集群扩容 1、集群健康 全文检索elasticsearch入门,看这篇就够了
文章图片

image-20210920221154778
集群的健康状态有三种:绿色 green、黄色 yellow、红色 red
绿色(健康):所有的主分片和副分片都正常运行
黄色(亚健康):所有主分片正常运行,但有副分片没正常运行
红色(不健康):有主分片没正常运行
2、扩容 扩容一般分为两种,垂直和水平
1)、垂直扩容
升级服务器,买性能更好的服务器替换原有的服务器,不过这种扩容不推荐,毕竟单台机器的性能总是有瓶颈的
2)、水平扩容
水平扩容也叫横向扩容,就是增加服务器数量,多台普通的服务器组织在一起形成强大的计算能力。俗话说:团结就是力量。
四、浏览器插件 head 插件是 ES 的一个可视化插件,类似于 navicat 和 mysql 的关系。head 插件是一个用来浏览、与 ES 数据进行交互的 web 前端展示插件,是一个用来监视 ES 状态的客户端插件。
以下是插件的一些简单介绍
全文检索elasticsearch入门,看这篇就够了
文章图片

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" } } } }

全文检索elasticsearch入门,看这篇就够了
文章图片

image-20210920232241959
  • 查询 keyword\_name,由于 keyword\_name 类型是 keyword,不会分词,所以 zhen 无法搜索到数据
全文检索elasticsearch入门,看这篇就够了
文章图片

image-20210920232950219
  • 查询 english\_name,同 text\_name,可以搜到
全文检索elasticsearch入门,看这篇就够了
文章图片

image-20210920233814208
  • 查询 english\_name.keyword,同 keyword\_name,无法搜索到结果
全文检索elasticsearch入门,看这篇就够了
文章图片

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 daxia 2. keyword_name:daxia zhen 3. keyword_name:I am zhen daxia 4. 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后端干货
你的支持是对我不断创作的极大鼓励,咱们下期见。
全文检索elasticsearch入门,看这篇就够了
文章图片

    推荐阅读