文章目录
- 前言
- 3 文档操作
- 3.1 新增文档
- 3.2 查询文档
- 3.3 修改文档
- 3.3.1 全量修改
- 3.3.2 增量修改
- 3.4 删除文档
- 4 RestAPI
- 4.1 创建数据库和表
- 4.2 创建项目
- 4.3 mapping映射分析
- 4.4 初始化客户端
- 4.5 创建索引库
- 4.6 判断索引库是否存在
- 4.7 删除索引库
- 5 RestClient操作文档
- 5.1 准备工作
- 5.2 新增文档
- 5.3 查询文档
前言
ElasticSearch学习笔记(一)倒排索引、ES和Kibana安装、索引操作
3 文档操作
3.1 新增文档
语法:
POST /{索引库名}/_doc/{文档id}
{"字段1": "值1","字段2": "值2","字段3": {"子属性1":"值3","子属性2":"值4"}// ...
}
3.2 查询文档
语法:
GET /{索引库名}/_doc/{文档id}
3.3 修改文档
3.3.1 全量修改
全量修改是覆盖原来的文档,其本质是先根据指定的id删除文档(id对应的文档不存在也可以),再新增一个相同id的文档。
语法:
PUT /{索引库名}/_doc/{文档id}
{"字段1": "值1","字段2": "值2","字段3": {"子属性1":"值3","子属性2":"值4"}// ...
}
3.3.2 增量修改
增量修改是只修改指定id匹配的文档中的部分字段。
语法:
POST /{索引库名}/_update/{文档id}
{"doc": {"修养修改的字段": "新值"}
}
3.4 删除文档
语法:
DELETE /{索引库名}/_doc/{文档id}
4 RestAPI
ES官方提供了各种不同语言的客户端用来操作ES,这些客户端的本质是组装DSL语句,通过Http请求发送给ES。其官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html
其中Java语言的客户端分为两种:
本文章学习的是high-level REST client。
4.1 创建数据库和表
CREATE DATABASE hsgx;
USE hsgx;
CREATE TABLE tb_hotel (`id` BIGINT(20) NOT NULL PRIMARY KEY COMMENT '酒店id',`name` VARCHAR(255) NOT NULL COMMENT '酒店名称',`address` VARCHAR(255) NOT NULL COMMENT '酒店地址',`price` INT(10) NOT NULL COMMENT '酒店价格',`score` INT(2) NOT NULL COMMENT '酒店评分',`brand` VARCHAR(32) NOT NULL COMMENT '酒店品牌',`city` VARCHAR(32) NOT NULL COMMENT '所在城市',`star_name` VARCHAR(16) NOT NULL COMMENT '酒店星级',`business` VARCHAR(255) NOT NULL COMMENT '商圈',`latitude` VARCHAR(32) NOT NULL COMMENT '纬度',`longitude` VARCHAR(32) NOT NULL COMMENT '经度',`pic` VARCHAR(255) DEFAULT NULL COMMENT '酒店图片'
);INSERT INTO tb_hotel(`id`, `name`, `address`, `price`, `score`, `brand`, `city`, `star_name`, `business`, `latitude`, `longitude`, `pic`)
VALUES (1, '白天鹅', '中山路', 888, 5, '白天鹅', '广州', '五星', '太古汇', '123.456', '456.748', 'a.png'),
(2, '希尔顿', '南京路', 456, 4.5, '希尔顿', '上海', '四星', '外滩', '123.456', '456.748', 'b.png');
4.2 创建项目
在IDEA中创建一个maven项目,结构如下:
4.3 mapping映射分析
mapping映射分析要考虑的信息包括:
- 字段名:参考表结构。
- 字段数据类型:参考表结构。
- 是否参与搜索:根据具体业务进行判断。
- 是否需要分词:根据具体内容进行判断,如果内容是一个整体就无需分词,反之则要分词。
- 分词器是什么:可以统一使用ik_max_word。
对应到tb_hotel
表,我们可以新建如下索引:
PUT /hotel
{"mappings": {"properties": {"id": {"type": "integer"},"name":{"type": "text","analyzer": "ik_max_word","copy_to": "all"},"address":{"type": "text","analyzer": "ik_max_word","index": false},"price":{"type": "integer"},"score":{"type": "integer"},"brand":{"type": "keyword","copy_to": "all"},"city":{"type": "keyword","copy_to": "all"},"starName":{"type": "keyword"},"business":{"type": "keyword"},"pic":{"type": "keyword","index": false},"location":{"type": "geo_point"},"all":{"type": "text","analyzer": "ik_max_word"}}}
}
其中,有两个比较特殊的字段:
- location:地理坐标,类型是
geo_point
,表示由经度(latitude)和纬度(longitude)确定一个点。 - all:一个组合字段,其目的是将多字段的值 利用
copy_to
属性合并,提供给用户搜索。在上面的例子中,name
、brand
、city
字段会合并到一起。
4.4 初始化客户端
Java客户端中,与ES一切交互都封装在一个名为RestHighLevelClient
的类中,必须先完成这个对象的初始化,建立与ES的连接。主要步骤如下:
- 1)引入依赖,注意版本号和安装的ES版本一致
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version>
</dependency>
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>7.12.1</version>
</dependency>
<dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.12.1</version>
</dependency>
- 2)初始化RestHighLevelClient
private RestHighLevelClient client;@Before
void setUp() {this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.153.128:9200")));
}@After
void close() throws IOException {this.client.close();
}
4.5 创建索引库
private static final String DSL = "{\n" +" \"mappings\": {\n" +" \"properties\": {\n" +" \"id\": {\n" +" \"type\": \"integer\"\n" +" },\n" +" \"name\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\",\n" +" \"copy_to\": \"all\"\n" +" },\n" +" \"address\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\",\n" +" \"index\": false\n" +" },\n" +" \"price\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"score\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"brand\":{\n" +" \"type\": \"keyword\",\n" +" \"copy_to\": \"all\"\n" +" },\n" +" \"city\":{\n" +" \"type\": \"keyword\",\n" +" \"copy_to\": \"all\"\n" +" },\n" +" \"starName\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"business\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"pic\":{\n" +" \"type\": \"keyword\",\n" +" \"index\": false\n" +" },\n" +" \"location\":{\n" +" \"type\": \"geo_point\"\n" +" },\n" +" \"all\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\"\n" +" }\n" +" }\n" +" }\n" +"}";@Test
public void testCreateHotelIndex() throws IOException {// 1.参数为索引库名称CreateIndexRequest createIndexRequest = new CreateIndexRequest("hotel");// 2.设置mapping映射createIndexRequest.source(DSL, XContentType.JSON);// 3.发起创建索引库请求client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
}
由以上代码可知,创建索引库的步骤主要又三步:
- 1)创建Request对象。创建索引库的操作对应的Request对象是CreateIndexRequest。
- 2)设置mapping映射,其实就是DSL的JSON参数部分。因为JSON字符串很长,所以定义了一个静态字符串常量来表示,让代码看起来更加优雅。
- 3)发送创建索引库请求,
client.indices()
方法的返回值是IndicesClient类型,封装了所有与索引库操作有关的方法。
执行以上单元测试,在DevTools工具中查询该索引库:
4.6 判断索引库是否存在
判断索引库是否存在,本质是使用GET
命令查询索引库,因此它对应的Request对象是GetIndexRequest。
@Test
public void testExistsHotelIndex() throws IOException {// 1.参数为索引库名称GetIndexRequest request = new GetIndexRequest("hotel");// 2.发送请求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);// 3.输出System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
}
执行以上单元测试,结果如下:
4.7 删除索引库
删除索引库对应的Request对象是DeleteIndexRequest。
@Test
public void testDeleteHotelIndex() throws IOException {// 1.参数为索引库名称DeleteIndexRequest request = new DeleteIndexRequest("hotel");// 2.发送请求client.indices().delete(request, RequestOptions.DEFAULT);
}
执行以上单元测试,在DevTools工具中查询该索引库:
5 RestClient操作文档
5.1 准备工作
由于上文定义的索引库hotel
的mapping映射与数据库表结构有一些差异,因此还需要定义一个新的实体类,与索引库的mapping映射对应起来:
@Data
@NoArgsConstructor
public class HotelDoc {private Long id;private String name;private String address;private Integer price;private Integer score;private String brand;private String city;private String starName;private String business;private String location;private String pic;public HotelDoc(Hotel hotel) {this.id = hotel.getId();this.name = hotel.getName();this.address = hotel.getAddress();this.price = hotel.getPrice();this.score = hotel.getScore();this.brand = hotel.getBrand();this.city = hotel.getCity();this.starName = hotel.getStarName();this.business = hotel.getBusiness();this.location = hotel.getLatitude() + ", " + hotel.getLongitude();this.pic = hotel.getPic();}
}
主要的区别在于,将latitude
、longitude
两个字段合并为location
一个字段。
5.2 新增文档
新增文档的DSL语句示例如下:
POST /hotel/_doc/1
{"name": "白天鹅","score": 5
}
对应的Java代码如下:
@Test
public void testCreateDocIndex() throws IOException {// 1.POST /hotel/_doc/1 { "name": "白天鹅", "score": 5 }IndexRequest request = new IndexRequest("hotel").id("1");request.source("{\"name\": \"白天鹅\", \"score\": 5}", XContentType.JSON)// 2.发送请求client.index(request, RequestOptions.DEFAULT);
}
执行以上单元测试,在DevTools工具中查询该文档:
下面实现把数据库tb_hotel
表的数据读取出来,并保存到ES中:
@Test
public void testSaveHotel() throws IOException {// 1.根据id查询酒店数据Hotel hotel = hotelService.getById(2);// 2.转换为文档类型HotelDoc hotelDoc = new HotelDoc(hotel);// 3.将HotelDoc转jsonString json = JSON.toJSONString(hotelDoc);// 4.准备Request对象IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());// 5.准备Json文档request.source(json, XContentType.JSON);// 6.发送请求client.index(request, RequestOptions.DEFAULT);
}
执行以上单元测试,在DevTools工具中查询该文档:
5.3 查询文档
新增文档的DSL语句示例如下:
GET /hotel/_doc/2
对应的Java代码如下:
@Test
public void testQueryHotelDoc() throws IOException {// 1.创建Request对象GetRequest request = new GetRequest("hotel", "2");// 2.发送请求GetResponse response = client.get(request, RequestOptions.DEFAULT);// 3.解析结果String json = response.getSourceAsString();HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);System.out.println(hotelDoc);
}
执行以上单元测试,结果如下:
…
本节完,更多内容请查阅分类专栏:微服务学习笔记
感兴趣的读者还可以查阅我的另外几个专栏:
- SpringBoot源码解读与原理分析
- MyBatis3源码深度解析
- Redis从入门到精通
- MyBatisPlus详解
- SpringCloud学习笔记