1.Elasticsearch基本知识
1.基本认识和安装
Elasticsearch是由elastic公司开发的一套搜索引擎技术,它是elastic技术栈中的一部分。完整的技术栈包括:
-
Elasticsearch:用于数据存储、计算和搜索
-
Logstash/Beats:用于数据收集
-
Kibana:用于数据可视化
整套技术栈被称为ELK,经常用来做日志收集、系统监控和状态分析等等;
Kibana是elastic公司提供的用于操作Elasticsearch的可视化控制台。它的功能非常强大,包括:
-
对Elasticsearch数据的搜索、展示
-
对Elasticsearch数据的统计、聚合,并形成图形化报表、图形
-
对Elasticsearch的集群状态监控
-
它还提供了一个开发控制台(DevTools),在其中对Elasticsearch的Restful的API接口提供了语法提示
安装elasticsearch
执行如下代码,并访问9200端口
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network hm-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1
安装Kibana
执行如下代码,并访问5601端口
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=hm-net \
-p 5601:5601 \
kibana:7.12.1
2.倒排索引
正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程。
而倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程。
正向索引
优点:
-
可以给多个字段创建索引
-
根据索引字段搜索、排序速度非常快
缺点:
根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
倒排索引
优点:
-
根据词条搜索、模糊搜索时,速度非常快
缺点:
-
只能给词条创建索引,而不是字段
-
无法根据字段做排序
3.IK分词器
Elasticsearch的关键就是倒排索引,而倒排索引依赖于对文档内容的分词,而分词则需要高效、精准的分词算法,IK分词器就是这样一个中文分词算法。
需要将中文分词器挂载到es的数据卷上
官方默认方式
POST /_analyze
{
"analyzer": "standard",
"text": "世界人民大团结万岁"
}
IK分词器包含两种模式:
-
ik_smart
:智能语义切分 -
ik_max_word
:最细粒度切分
POST /_analyze
{
"analyzer": "ik_smart",
"text": "世界人民大团结万岁"
}
POST /_analyze
{
"analyzer": "ik_max_word",
"text": "世界人民大团结万岁"
}
有些词语字典里面没有,需要自己手动添加,还可以对某些字或词语不进行分词
在config目录下如图三个文件
添加自己的词语和不希望分词的词语即可
4.mysql和es的对比
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 |
2.索引库的操作
1.Mapping映射属性
Mapping是对索引库中文档的约束,常见的Mapping属性包括:
-
type
:字段数据类型,常见的简单类型有:-
字符串:
text
(可分词的文本)、keyword
(精确值,例如:品牌、国家、ip地址) -
数值:
long
、integer
、short
、byte
、double
、float
、 -
布尔:
boolean
-
日期:
date
-
对象:
object
-
-
index
:是否创建索引,默认为true
-
analyzer
:使用哪种分词器 -
properties
:该字段的子字段
2.索引库的CRUD
创建索引库
基本语法:
-
请求方式:
PUT
-
请求路径:
/索引库名
,可以自定义 -
请求参数:
mapping
映射
代码如下:
#新增
PUT /pxy
{
"mappings": {
"properties": {
"info":{
"type": "text",
"analyzer": "ik_smart"
},
"age":{
"type": "byte"
},
"email":{
"type": "keyword",
"index": false
},
"name":{
"type": "object",
"properties": {
"firstname":{
"type": "keyword"
},
"lastname":{
"type": "keyword",
"index":false
}
}
}
}
}
}
查询索引库
基本语法:
-
请求方式:GET
-
请求路径:/索引库名
-
请求参数:无
代码如下:
#查询
GET /pxy
修改索引库
无法修改索引库,但是可以添加新的字段
#es不支持修改,但可以添加
PUT /pxy/_mapping
{
"properties":{
"age":{
"type":"byte"
}
}
}
删除索引库
语法:
-
请求方式:DELETE
-
请求路径:/索引库名
-
请求参数:无
#删除
DELETE /pxy
3.文档的操作
1.文档的CRUD
增加数据
#新增数据
POST /pxy/_doc/1
{
"info":"我是大帅哥",
"age":18,
"email":"123456@qq.com",
"name":{
"firstname":"潘",
"lastname":"xy"
}
}
查询数据
#查询数据
GET /pxy/_doc/1
删除数据
#删除数据
DELETE /pxy/_doc/1
修改数据
分为全量修改和局部修改。全量修改是删除原来的数据在新增数据,局部修改只是把原来的数据修改掉。
#修改数据
#全量修改
Put /pxy/_doc/1
{
"info":"我是大帅哥",
"age":17,
"email":"123456@qq.com",
"name":{
"firstname":"p",
"lastname":"xy"
}
}
#局部修改
POST /pxy/_update/1
{
"doc": {
"info":"无敌是多么寂寞",
"name":{
"firstname":"wd",
"lastname":"jm"
}
}
}
2.批量处理
一次处理多个请求
批处理采用POST请求,基本语法如下:
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
其中:
-
index
代表新增操作-
_index
:指定索引库名 -
_id
指定要操作的文档id -
{ "field1" : "value1" }
:则是要新增的文档内容
-
-
delete
代表删除操作-
_index
:指定索引库名 -
_id
指定要操作的文档id
-
-
update
代表更新操作-
_index
:指定索引库名 -
_id
指定要操作的文档id -
{ "doc" : {"field2" : "value2"} }
:要更新的文档字段
-
批量新增操作
POST /_bulk
{"index":{"_index":"pxy","_id":"2"}}
{"info":"我是大帅哥","age":17,"email":"123456@qq.com", "name":{"firstname":"p","lastname":"xy"}}
{"index":{"_index":"pxy","_id":"3"}}
{"info":"我是大帅哥","age":17,"email":"123456@qq.com", "name":{"firstnam:"p","lastname":"xy"}}
批量删除操作
POST /_bulk
{"delete":{"_index":"pxy","_id":"2"}}
{"delete":{"_index":"pxy","_id":"3"}}
4.用java程序操作es
1.注册RestHighLevelClient
在elasticsearch提供的API中,与elasticsearch一切交互都封装在一个名为RestHighLevelClient
的类中,必须先完成这个对象的初始化,建立与elasticsearch的连接。
导入依赖:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.12.1<version>
</dependency>
初始化代码如下:
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.145.129:9200")
));
2.对索引进行操作
创建索引
@Test
public void createindex() throws IOException {
//准备request对象
CreateIndexRequest request = new CreateIndexRequest("pxy");
//准备请求参数
request.source(MAPPING_TEMPLATE, XContentType.JSON);
//发送请求体
client.indices().create(request, RequestOptions.DEFAULT);
}
private final static String MAPPING_TEMPLATE="{\n" +
" \"mappings\": {\n" +
" \"properties\": {\n" +
" \"id\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"name\":{\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" },\n" +
" \"price\":{\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"stock\":{\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"image\":{\n" +
" \"type\": \"keyword\",\n" +
" \"index\": false\n" +
" },\n" +
" \"category\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"brand\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"sold\":{\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"commentCount\":{\n" +
" \"type\": \"integer\",\n" +
" \"index\": false\n" +
" },\n" +
" \"isAD\":{\n" +
" \"type\": \"boolean\"\n" +
" },\n" +
" \"updateTime\":{\n" +
" \"type\": \"date\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
}
查询索引
@Test
public void getindex() throws IOException {
//准备request对象
GetIndexRequest request = new GetIndexRequest("pxy");
//发送请求体
// GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
// System.out.println("返回参数"+response);
//判断请求参数是否存在
Boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println("exists="+exists);
}
删除索引
@Test
public void deleteindex() throws IOException {
//准备request对象
DeleteIndexRequest request = new DeleteIndexRequest("pxy");
//发送请求体
client.indices().delete(request, RequestOptions.DEFAULT);
}
3.对文档进行操作
新增文档
@Test
void testAddDocument() throws IOException {
// 1.准备Request对象
IndexRequest request = new IndexRequest("pxy").id("1");
// 2.准备Json文档
request.source({}, XContentType.JSON);
// 3.发送请求
client.index(request, RequestOptions.DEFAULT);
}
查询文档
@Test
void testGetDocumentById() throws IOException {
// 1.准备Request对象
GetRequest request = new GetRequest("pxy").id("1");
// 2.发送请求
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 3.获取响应结果中的source
String json = response.getSourceAsString();
System.out.println("json= " + json);
}
删除文档
@Test
void testDeleteDocument() throws IOException {
// 1.准备Request,两个参数,第一个是索引库名,第二个是文档id
DeleteRequest request = new DeleteRequest("pxy", "1");
// 2.发送请求
client.delete(request, RequestOptions.DEFAULT);
}
修改文档
修改一共两种方式:
-
全量修改:本质是先根据id删除,再新增
-
局部修改:修改文档中的指定字段值
在RestClient的API中,全量修改与新增的API完全一致,判断依据是ID:
-
如果新增时,ID已经存在,则修改
-
如果新增时,ID不存在,则新增
这里不再赘述,我们主要关注局部修改的API即可。
@Test
void testUpdateDocument() throws IOException {
// 1.准备Request
UpdateRequest request = new UpdateRequest("pxy", "1");
// 2.准备请求参数
request.doc(
"price", 58800,
"commentCount", 1
);
// 3.发送请求
client.update(request, RequestOptions.DEFAULT);
}
批量处理文档
@Test
void testBulk() throws IOException {
// 1.创建Request
BulkRequest request = new BulkRequest();
// 2.准备请求参数
//新增文档
request.add(new IndexRequest("items").id("1").source("json doc1", XContentType.JSON));
request.add(new IndexRequest("items").id("2").source("json doc2", XContentType.JSON));
//删除文档
request.add(new DeleteRequest("items").id("2"));
// 3.发送请求
client.bulk(request, RequestOptions.DEFAULT);
}