分布式搜索引擎ElasticSearch-1
Posted endorphinnnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式搜索引擎ElasticSearch-1相关的知识,希望对你有一定的参考价值。
1、初识ES
1.1.了解ES
1.1.1.作用
开源搜索引擎,从海量数据中快速找到需要的内容
1.1.2.ELK技术栈
elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域。而elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。
1.1.3.elasticsearch和Lucene
elasticsearch底层是基于lucene来实现的。
Lucene是一个Java语言的搜索引擎类库,提供了搜索引擎的核心API
Lucene优势:以扩展、高性能(基于倒排索引)
Lucene缺点:只限于Java语言开发、学习曲线陡峭、不支持水平扩展
1.2.倒排索引
倒排索引的概念是基于mysql这样的正向索引。
1.2.1.正向索引
根据id建立索引。id和title建表,如果基于title做模糊查询,那么只能根据id进行逐行扫描。
是根据文档找词条的过程。
优点:
- 可以给多个字段创建索引
- 根据索引字段搜索、排序速度非常快
缺点: - 根据非索引字段或者索引字段中的部分词条查找时,只能全表扫描
1.2.2.倒排索引
有两个非常重要的概念:
- 文档(Document):用来搜索的数据,其中的每一条数据就是一个文档。
- 词条(Term):对文档数据或用户搜索数据,利用某种算法分词,得到的具体含义的词语就是词条。分词。
创建倒排索引是对正向索引的一种特殊处理:
- 将每一个文档的数据利用算法分词,得到一个个词条
- 创建表,每行数据包括词条、词条所在文档id、位置等信息
- 因为词条唯一性,可以给词条创建索引。
是根据词条找文档的过程。
优点:
- 根据词条搜索、模糊搜索时,速度非常快
缺点: - 只能给词条创建索引,而不是字段
- 无法根据字段做排序
1.3.ES的一些概念
文档
es是面向文档存储的,可以是数据库的一条商品数据、一个订单信息。文档数据会被序列化为json格式后存储在es中。
字段
json文档中往往包含很多的字段(field),类似于数据库中的列。
索引
相同类型的文档的集合,可以把索引当做数据库中的表。
映射
数据库的表会有约束信息,用来定义表的结构、字段的名称、类型等信息。因此索引库中的映射,就是索引中文档的字段约束信息,类似表的结构约束。
mysql
擅长事务类型操作,可以确保数据的安全和一致性
elasticsearch
擅长海量数据的搜索、分析、计算
MySQL | Elasticsearch | 说明 |
---|---|---|
Table | Index | 索引(index),就是文档的集合,类似数据库的表(table) |
Row | Document | 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式 |
Column | Field | 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column) |
Schema | Mapping | Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema) |
SQL | DSL | DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD |
- 对于安全性较高的写操作,使用mysql实现
- 对于查询性能较高的搜索需求,使用es实现
- 两者再基于某种方式,实现数据的同步,保证一致性
1.4.分词器
作用
- 创建倒排索引时对文档分词
- 用户搜索时,对输入的内容分词
模式
- ik_smart:只能切分,粗粒度
- ik_max_work:最细切分,细粒度
如何扩展词条、停用词条
- 利用config牡蛎的IkAnalyzer.cfg.xml文件添加拓展词典和停用词典
- 在词典中添加拓展词条或者停用词条
在ext.dic文件里添加拓展词条,在stopword.dic文件里添加停用词条。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典-->
<entry key="ext_dict">ext.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典 *** 添加停用词词典-->
<entry key="ext_stopwords">stopword.dic</entry>
</properties>
2、索引库操作
Rest(PUT、GET、DELETE)
2.1.mapping映射属性
mapping是对索引库中文档的约束,常见的mapping属性包括:
- type:字段数据类型,常见的简单类型有:
- 字符串:text(可分词的文本)、keyword(精确值,例如品牌、国家等不分词)
- 数值:long、integer等
- 布尔:boolean
- 日期:date
- 对象:object
- index:是否创建索引,默认为true
- analyzer:使用哪种分词器
- properties:该字段的子字段
2.2.索引库的CRUD
2.2.1.创建索引库
# PUT /索引库名称
PUT /heima
"mappings":
"properties":
"info":
"type": "text",
"analyzer": "ik_smart"
,
"email":
"type": "keyword",
"index": "falsae"
,
"name":
"properties":
"firstName":
"type": "keyword"
,
// ... 略
2.2.2.修改索引库(添加字段)
索引库一旦创建,无法修改mapping中已有的字段,但是允许添加新字段到mapping中。
PUT /索引库名/_mapping
"properties":
"新字段名":
"type": "integer"
2.2.3.查看索引库
GET /索引库名
2.2.4.删除索引库
DELETE /索引库名
3、文档操作
3.1.新增文档
可以用post和put,但是post新增不指定id系统会自动新建一个id;而get不指定id系统不会分配。
POST /索引库名/_doc/文档id
"字段1": "值1",
"字段2": "值2",
"字段3":
"子属性1": "值3",
"子属性2": "值4"
,
// ...
3.2.查询文档
GET /索引库名称/_doc/id
3.3.删除文档
DELETE /索引库名/_doc/id值
3.4.修改文档
- 全量修改(id存在,即为修改;不存在,即为新增)
会删除旧文档,添加新文档
POST /索引库名/_doc/文档id
"字段1": "值1",
"字段2": "值2",
"字段3":
"子属性1": "值3",
"子属性2": "值4"
,
// ...
- 增量修改
修改指定字段的值
POST /索引库名/_update/文档id
"doc":
"字段名": "新的值",
4、RestAPI
ES中支持两种地理坐标数据类型:
- geo_point:点
- geo_shape:多个点连接形成的形状
copy_to:将当前字段拷贝到指定字段
核心是client.indices()方法来获取索引库的操作对象。
4.1.初始化RestClient
在elasticsearch提供的API中,与elasticsearch一切交互都封装在一个名为RestHighLevelClient的类中,必须先完成这个对象的初始化,建立与elasticsearch的连接:
1、导入es的RestHighLevelClient依赖:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
2、因为SpringBoot默认的ES版本是7.6.2,所以我们需要覆盖默认的ES版本:
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
3、初始化RestHighLevelClient
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
//填写自己的IP值和端口
HttpHost.create("http://192.168.150.101:9200")
));
4.2.创建索引库
- 1)创建Request对象。因为是创建索引库的操作,因此Request是CreateIndexRequest。
- 2)添加请求参数,其实就是DSL的JSON参数部分。因为json字符串很长,这里是定义了静态字符串常量MAPPING_TEMPLATE,让代码看起来更加优雅。
- 3)发送请求,client.indices()方法的返回值是IndicesClient类型,封装了所有与索引库操作有关的方法。
//MAPPING_TEMPLATE是自己定义的格式
@Test
void createHotelIndex() throws IOException
// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest("hotel");
// 2.准备请求的参数:DSL语句
request.source(MAPPING_TEMPLATE, XContentType.JSON);
// 3.发送请求
client.indices().create(request, RequestOptions.DEFAULT);
4.3.删除索引库
- 1)创建Request对象。这次是DeleteIndexRequest对象
- 2)准备参数。这里是无参
- 3)发送请求。改用delete方法
@Test
void testDeleteHotelIndex() throws IOException
// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
// 2.发送请求
client.indices().delete(request, RequestOptions.DEFAULT);
4.4.判断索引库是否存在
- 1)创建Request对象。这次是GetIndexRequest对象
- 2)准备参数。这里是无参
- 3)发送请求。改用exists方法
@Test
void testExistsHotelIndex() throws IOException
// 1.创建Request对象
GetIndexRequest request = new GetIndexRequest("hotel");
// 2.发送请求
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
// 3.输出
System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
5、RestClient操作文档
数据库结构和索引库结构会不一致,所以需要新建类库来使结构保持一致。
5.1.新增文档
@Test
void testAddDocument() throws IOException
// 1.根据id查询酒店数据
Hotel hotel = hotelService.getById(61083L);
// 2.转换为文档类型
HotelDoc hotelDoc = new HotelDoc(hotel);
// 3.将HotelDoc转json
String json = JSON.toJSONString(hotelDoc);
// 1.准备Request对象
IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
// 2.准备Json文档
request.source(json, XContentType.JSON);
// 3.发送请求
client.index(request, RequestOptions.DEFAULT);
5.2.查询文档
@Test
void testGetDocumentById() throws IOException
// 1.准备Request
GetRequest request = new GetRequest("hotel", "61082");
// 2.发送请求,得到响应
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.解析响应结果
String json = response.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
5.3.删除文档
@Test
void testDeleteDocument() throws IOException
// 1.准备Request
DeleteRequest request = new DeleteRequest("hotel", "61083");
// 2.发送请求
client.delete(request, RequestOptions.DEFAULT);
5.4.修改文档
- 全量修改:与新增的API完全一致,如果新增时id已存在,则修改;如果新增时id不存在,则新增。
- 增量修改:
@Test
void testUpdateDocument() throws IOException
// 1.准备Request
UpdateRequest request = new UpdateRequest("hotel", "61083");
// 2.准备请求参数
request.doc(
"price", "952",
"starName", "四钻"
);
// 3.发送请求
client.update(request, RequestOptions.DEFAULT);
5.5.批量导入文档
BulkRequest做批量操作,有批量的增、删、查操作。
@Test
void testBulkRequest() throws IOException
// 批量查询酒店数据
List<Hotel> hotels = hotelService.list();
// 1.创建Request
BulkRequest request = new BulkRequest();
// 2.准备参数,添加多个新增的Request
for (Hotel hotel : hotels)
// 2.1.转换为文档类型HotelDoc
HotelDoc hotelDoc = new HotelDoc(hotel);
// 2.2.创建新增文档的Request对象
request.add(new IndexRequest("hotel")
.id(hotelDoc.getId().toString())
.source(JSON.toJSONString(hotelDoc), XContentType.JSON));
// 3.发送请求
client.bulk(request, RequestOptions.DEFAULT);
以上是关于分布式搜索引擎ElasticSearch-1的主要内容,如果未能解决你的问题,请参考以下文章
Elasticsearch 分布式搜索引擎 -- 初识elasticsearch(了解ES倒排索引es的一些概念安装eskibana)