简介:
- 全文搜索属于最常见的需求,开源的Elasticserch是目前全文搜索引擎的首选.
- 它可以快速地储存,搜索,和分析海量数据.维基百科,Stack OverFlow,github,都采用它
- Elastic底层是开源库,Lucene,但是,你没法直接用Lucene,必须自己写代码去调用它的接口,Elastic是Lucene的封装,提供了REST API 的操作接口,开箱即用. 官网参考文档
一,基本概念
1. Index(索引)
- 动词,相当于mysql中的insert操作(索引一条数据)
- 名词,相当于mysql中的Database
2. Type(类型)
-
在Index(索引)中,可以定义一个或多个类型
-
类似于mysql中的table,每一种类型的数据放在一起
3. Document(文档)
- 保存在某个索引(Index)下的,某种类型(Type)的一个数据(Document),文档是JSON格式的,Document就像是mysql中的某个Table里面的内容.
二,Docker安装ES
-
elasticsearch:
-
docker run --name elasticsearch -p 9200:9200 -p 9300:9300
-e “discovery.type=single-node”
-e ES_JAVA_OPTS="-Xms64m -Xmx128m"
-v /dockerData/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
-v /dockerData/elasticsearch/data:/usr/share/elasticsearch/data
-v /dockerData/elasticsearch/plugins:/usr/share/elasticsearch/plugins
-d elasticsearch:7.8.0 -
discovery.type=single-node:单节点启动
-
ES_JAVA_OPTS="-Xms64m -Xmx128m:初始64M,elasticsearch最大占用128M
-
-
kibana(图形化操作elasticsearch,不装也行,原理是发请求,postman可以代替):
-
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://39.100.66.142:9200 -p 5601:5601 -d kibana:7.8.0
-
ELASTICSEARCH_HOSTS:配置es的地址
-
三, 初步检索
1. _cat
- GET /_cat/nodes : 查看所有节点
- GET /_cat/health : 查看es健康状态
- GET /_cat/master : 查看主节点
- GET /_cat/indices :查看所有索引 类似 show databases
2. 索引一个文档(保存)
- 保存一个数据,保存在哪个索引的哪个类型下,指定用哪一个唯一标识
- PUT /customer/external/1 body: {“name”:“特朗普nb”} 在customer索引下的external类型下保存1号数据
- 其实PUT和POST都可以实现保存,区别:
- POST新增/修改,如果不指定id,会自动生成id 做新增操作,如果指定id并且指定的id已经存在,那么就会做修改操作,并增加版本号
- PUT新增/修改,PUT必须指定id,不指定id会报错,所以一般用PUT做修改操作
3. 查询文档
-
GET /customer/external/1
-
结果:
{ "_index": "customer", //索引 "_type": "external", //分类 "_id": "1", //id "_version": 1, //版本 "_seq_no": 0, //并发控制字段,每次更新就会+1,用来做乐观锁 "_primary_term": 1, //同上,主分片重新分配,如果重启,就会发生变化 "found": true, "_source": { //真正的内容 "name": "特朗普nb" } } //乐观锁修改实现,更新携带 ?if_seq_no=0&if_primary_term=1 ,只想对_seq_no值为0,_primary_term为1的数据进行修改,如果在这之前有人修改了原数据,使这两个值发生改变,那么我将不继续修改抱409错误
4. 更新文档
-
POST customer/external/1/_update body:{“doc”:{“name”:“特朗普lj”}} 如果带上_update body中就要带上doc
-
POST customer/external/1 body:{“name”:“特朗普lj”}
-
PUT
-
区别:
- post带update : 会对比原来的数据,如果与原来一样,就什么都不做,version,seq_no都不变
- put和post(不带update):直接更新
5. 删除文档&索引
- DELETE /customer/external/1
- DELETE /customer
- 没有删除类型的操作
6.bulk批量API
-
POST customer/external/_bulk
-
body:
-
{“index”:{"_id":“1”}}
{“name”:“华盛顿”}
{“index”:{"_id":“2”}}
{“name”:“雷克顿”}
-
语法格式:
-
两行为一组 删除操作单独一行
{action:{metadata}
{request body}
action: 需要执行什么操作 index 保存操作
metadata: 原数据信息 哪个索引,哪个分类,哪个id 等等
request body 真正的请求体
-
复杂实例:
-
POST /_bulk
{“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”}}
{“doc”:{“title”:“My Update Blog Post”}}
-
官网提供的批量数据
-
四,进阶检索
1. Search API
-
ES支持两种基本方式检索:
- 一个是通过REST request URI 发送搜索参数(uri+检索参数)
- 另一个是通过 REST request body 来发送参数(uri+请求体)
-
检索信息
-
一切检索从_search开始
-
uri+检索参数进行检索
- GET bank/_search 检索bank下所有信息,包括type和docs
- GET bank/_search?q=*&sort=account_number:asc 请求参数方式检索(*查询所有,按照account_number字段升序)
-
uri+请求体进行检索(用postman get不能携带body,用post也可以检索)
-
GET bank/_search
-
//请求体遵循Query DSL语法规则 { "query":{ "match_all":{} }, "sort":[{ "account_number":"asc" }] }
-
-
响应结果:
- took :执行检索的耗时(毫秒)
- time_out : 是否超时
- _shards : 分片信息(搜索了多少个分片,以及成功,失败或跳过了多少个分片)
- max_score : 找到的最相关文件的分数
- hits.total.value : 找到了多少个匹配的文档
- hits.sort : 文档的排序位置(不按相关性得分排序时)
- hits._score : 文档的相关性得分(使用时不适用
match_all
)
-
2. Query DSL
(1). 基本语法格式
-
ES提供了一个可以执行查询的json风格DSL(domain-specific language 领域特定语言).这个被称为 Query DSL.该查询语言非常全面.
-
典型结构:
-
{
QUERY_NAME : {
ARGUMENT : VALUE,
ARGUMENT : VALUE…
},
QUERY_NAME : {
ARGUMENT : VALUE,
ARGUMENT : VALUE…
}…
}
-
-
针对某个字段:
-
{
QUERY_NAME : {
FIELD_NAME:{
ARGUMENT : VALUE,
ARGUMENT : VALUE…
}
}
}
-
(2). 返回部分字段
-
{
QUERY_NAME : {
ARGUMENT : VALUE,
ARGUMENT : VALUE…
},
“from”:0,
“size”: 5,
“_source”:[“age”,“balance”]
}
//从第0个开始,返回5条,只返回age和balance字段
(3). match 匹配查询
-
基本类型(非字符串),精准匹配(字段.keyword也能做精准匹配)
-
{ "query":{ "match":{ "account_number":20 } } } //匹配account_number=20的数据
-
-
字符串 全文检索
-
{ "query": { "match": { "address": "Perry" } } } //匹配address中包含Perry的所有数据 { "query": { "match": { "address": "Perry Argyle" } } } //并且根据空格进行分词 匹配adress中包含Perry或者Argyle或者Perry Argyle的所有数据
-
(4). match_phrase 短语匹配
-
将匹配值当成一个整体(不分词)进行检索
-
{ "query": { "match_phrase": { "address": "Perry Argyle" } } } //匹配adress中包含Perry Argyle的数据
-
(5). multi_match 多字段匹配
-
多个字段匹配指定值,会分词
-
{ "query": { "multi_match": { "query": "mill Tibbie", "fields": ["address","city"] } } } //匹配address或者city中包含mill或Tibbie或mill Tibbie的所有数据
-
(6). bool 复合查询
-
bool用来做复合查询,复合查询可以合并任何其他查询语句,包括复合查询,可以嵌套
-
{ "query": { "bool": { "must": [ {"match": { "gender": "M" }},{ "match": { "address": "mill" } } ], "must_not": [ {"match": { "age": 28 }} ] } } } //must 必须同时满足 相当于and 必须同时满足gender和address //must_not 必须同时不满足 must_not会被当成一个filter不会参与计算相关性得分 //should 期望 不一定要满足 当然,满足条件可以加分
-
(7). filter 结果过滤
- 并不是所有查询都会产生分数,特别是那些进用于过滤的文档,为了不计算分数,es会自动检查场景并且优化查询的执行
(8). term
- 和match功能类似,所以一般 全文检索字段用match,其他非text字段用term
(9). aggregations(执行聚合)
五. Mapping
1. mapping
-
mapping映射,是用来定义文档及其包含的字段的存储和索引方式的过程,例如
-
哪些字符串应该视为全文字段
-
哪些字段包含数字,日期或者地理位置
-
日期值的格式
-
自定义规则,用于控制动态添加字段的映射
2. 字段数据类型
- 每个字段都有一个数据type,如果没有指定,es会进行猜测,字段类型可以是:
- 简单类型 text,keyword,date,long,double,boolean或ip
- 支持JSON的分层性质类型,如 object和nested
- 或一种特殊类型 如geo_point,geo_shape或completion
3. mapping操作
- 在es7.0以后就已经不再推荐type,即由 index-type-document变为 index-document,无type的默认type为_doc
(1). 创建映射
-
//PUT /my_index { "mappings":{ "properties":{ "age":{"type":"integer"}, "email":{"type":"keyword"}, "mame":{"type":"text"} } } } //GET /my_index/_mapping 可以查看索引的映射
(2). 添加新的字段
-
//PUT /my_index/_mapping { "properties":{ "employee_id":{ "type":"keyword", "index":false } } } //index 字段是否参与检索,默认为true
(3). 更新映射
- 对于已经存在的映射字段,es不支持更新,如果想要实现更新,就必须创建新的索引,然后进行数据迁移
(4). 数据迁移
-
//POST _reindex 固定写法 { "source": { "index": "bank", "type": "account" }, "dest": { "index": "newbank" } } //把bank索引下类型为account的文档迁移(复制)到 newbank下(有type迁移到无type)
(5). 分词
- 一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流.例如 whitespace tokenizer遇到空白字符时分割文本,它会将文本"Quick fox jumps"分割为[“Quick”,“fox”,“jumps”],该tokenizer(分词器)还负责记录各个term(词条)的顺序或position(位置)(用于phrase短语和word proximity词邻近查询),以及term所代表的原始word(单词)的start(起始)和end(结束)的character offsets(字符偏移量)(用于高亮显示搜索内容),es提供了很多内置分词器,可以用来构建custom analyzers(自定义分词器)
ik分词器
-
安装: 在github上下载和es对应版本ik的zip文件,解压到es的plugins文件夹下即可
-
测试
-
//GET _analyze { "analyzer": "ik_smart", "text": "美国新增确诊再创新高" } //[美国,新增,确诊,再创新高] { "analyzer": "ik_max_word", "text": "美国新增确诊再创新高" } //[美国,新增,确诊,再创新高,再创,创新高,创新,新高] 最全匹配
-
-
自定义词库
- 修改es的config/IKAnalyzer.cfg.xml文件,导入自定义词库(可以用本地文件,也可以使用nginx导入远程词库)
六. Elasticsearch-Rest-Client
- 9300端口(tcp)
- spring-data-elasticsearch:transport-api.jar
- springboot版本不同,transport-api.jar不同,不能适配es版本
- 7.x已经不建议使用,预期8.x废弃
- spring-data-elasticsearch:transport-api.jar
- 9200端口(http)
- JestClient 非官方,更新慢
- RestTemplate,HttpClient 模拟发送http请求,ES很多操作需要自己封装,麻烦
- Elasticsearch-Rest_Client 官方RestClient,封装了ES操作,API层次分明,易上手(最终选择)
- es程序操作API