对es概念不熟悉的话,先去看上面的 '实用篇-ES-索引库和文档',不建议基础不牢就直接往下学
ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求来发送给ES。
官方文档地址: https://www.elastic.co/guide/en/elasticsearch/client/index.html
下面就使用java程序进行操作es,不再像上面那样使用浏览器页面进行操作es
在下面会逐步完成一个案例: 下载提供的hotel-demo.zip压缩包,解压后是hotel-demo文件夹,是一个java项目工程文件,按照条件创建索引库,索引库名为hotel,mapping属性根据数据库结构定义。还要下载一个tb_hotel.sql文件,作为数据库数据
hotel-demo.zip下载:https://cowtransfer.com/s/36ac0a9f9d9043
tb_hotel.sql下载: https://cowtransfer.com/s/716f049850a849
第一步: 把tb_hotel.sql文件导入进你的数据库
第二步:idea打开解压后的文件

第三步:在application.yml中配置正确的信息

在es中,mapping要考虑的问题: 字段名、数据类型、是否参与搜索、是否分词、如果分词那么分词器是什么。
我们刚刚在mysql导入了tb_hotel.sql,里面有很多数据,我们需要基于这些数据结构,去分析并尝试编写对应的es的mapping映射
先看mysql中的数据类型(已有),如下

根据mysql的数据类型等信息,编写es(没有,自己对着上面的sql写的)。注意经纬度在es里面是geo_point类型,且经纬度是写在一起的
- PUT /hotel
- {
- "mappings": {
- "properties": {
- "id":{
- "type": "keyword"
- },
- "name":{
- "type": "text",
- "analyzer": "ik_max_word"
- },
- "address":{
- "type": "keyword",
- "index":false
- },
- "price":{
- "type": "integer"
- },
- "score":{
- "type": "integer"
- },
- "brand":{
- "type": "keyword"
- },
- "city":{
- "type": "keyword"
- },
- "starName":{
- "type": "keyword"
- },
- "business":{
- "type": "keyword"
- },
- "location":{
- "type": "geo_point"
- },
- "pic":{
- "type":"keyword",
- "index": false
- }
- }
- }
- }
可以看到name,brand,score,city,starName等字段都要参与搜索,也就是用户可能根据多个关键字搜,查询条件是多个值,这时候可以用es提供的copy_to属性,把这些字段都拷贝到这个字段中,就可以实现在一个字段中搜到多个字段的内容了
下面演示把名字(name)、品牌(brand)和商圈(business)三个字段拷贝到all字段,代码如下
- PUT /hotel
- {
- "mappings": {
- "properties": {
- "id":{
- "type": "keyword"
- },
- "name":{
- "type": "text",
- "analyzer": "ik_max_word",
- "copy_to": "all"
- },
- "address":{
- "type": "keyword",
- "index":false
- },
- "price":{
- "type": "integer"
- },
- "score":{
- "type": "integer"
- },
- "brand":{
- "type": "keyword",
- "copy_to": "all"
- },
- "city":{
- "type": "keyword"
- },
- "starName":{
- "type": "keyword"
- },
- "business":{
- "type": "keyword",
- "copy_to": "all"
- },
- "location":{
- "type": "geo_point"
- },
- "pic":{
- "type":"keyword",
- "index": false
- },
- "all":{
- "type": "text",
- "analyzer": "ik_max_word"
- }
- }
- }
- }
操作主要是在idea的hotel-demo项目进行,hotel-demo项目(不是springcloud项目,只是springboot项目)是前面 '1. RestClient案例准备',跳过的可回去补
第一步: 在hotel-demo项目的pom.xml添加如下
- <properties>
- <java.version>1.8java.version>
- <elasticsearch.version>7.12.1elasticsearch.version>
- properties>
-
- <dependency>
- <groupId>org.elasticsearch.clientgroupId>
- <artifactId>elasticsearch-rest-high-level-clientartifactId>
- <version>7.12.1version>
- dependency>
第二步: 在hotel-demo项目的src/test/java/cn.itcast.hotel目录新建HotelIndexTest类,写入如下
- package cn.itcast.hotel;
-
- import org.apache.http.HttpHost;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestClientBuilder;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.junit.jupiter.api.AfterEach;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
-
- import java.io.IOException;
-
- public class HotelIndexTest {
-
- private RestHighLevelClient client;
-
- @Test
- void init(){
- System.out.println(client);
- }
-
- @BeforeEach
- void setUp(){
- this.client = new RestHighLevelClient(RestClient.builder(
- //指定你Centos7部署的es的主机地址
- HttpHost.create("http://192.168.229.129:9200")
- ));
- }
-
- @AfterEach
- void tearDown() throws IOException {
- this.client.close();
- }
-
- }
运行init方法,可以看到client的信息打印出来,表示初始化成功

不是通过kibana的浏览器控制台,通过DSL语句来进行操作es,在es里面创建索引库
而是通过上一节初始化的RestClient对象,在Java里面去操作es,创建es的索引库。根本不需要kibana做中间者
第一步: 在src/main/java/cn.itcast.hotel目录新建constants.HotelConstants类,里面写DSL语句,如下
其中长长的字符串就是我们在前面 '2. hotel数据结构分析' 里面写的。忘了怎么写出来的,可以回去看看
- package cn.itcast.hotel.constants;
-
- public class HotelConstants {
- public static final String MAPPING_TAMPLATE = "{\n" +
- " \"mappings\": {\n" +
- " \"properties\": {\n" +
- " \"id\":{\n" +
- " \"type\": \"keyword\"\n" +
- " },\n" +
- " \"name\":{\n" +
- " \"type\": \"text\",\n" +
- " \"analyzer\": \"ik_max_word\",\n" +
- " \"copy_to\": \"all\"\n" +
- " },\n" +
- " \"address\":{\n" +
- " \"type\": \"keyword\",\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" +
- " },\n" +
- " \"starName\":{\n" +
- " \"type\": \"keyword\"\n" +
- " },\n" +
- " \"business\":{\n" +
- " \"type\": \"keyword\",\n" +
- " \"copy_to\": \"all\"\n" +
- " },\n" +
- " \"location\":{\n" +
- " \"type\": \"geo_point\"\n" +
- " },\n" +
- " \"pic\":{\n" +
- " \"type\":\"keyword\",\n" +
- " \"index\": false\n" +
- " },\n" +
- " \"all\":{\n" +
- " \"type\": \"text\",\n" +
- " \"analyzer\": \"ik_max_word\"\n" +
- " }\n" +
- " }\n" +
- " }\n" +
- "}";
- }
第二步: 在hotel-demo项目的HotelIndexTest类,添加如下
- @Test
- void testCreateHotelIndex() throws IOException {
- //创建Request对象
- CreateIndexRequest request = new CreateIndexRequest("hotel");
- //请求参数,MAPPING_TEMPLATE是静态常量字符串,内容是创建索引库的DSL语句
- request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
- //发起请求
- client.indices().create(request, RequestOptions.DEFAULT);
- }
第三步: 确保下面的服务你都在Centos7里面启动了
- systemctl start docker # 启动docker服务
- docker restart es #启动elasticsearch容器
- docker restart kibana #启动kibana容器
第四步: 验证。运行HotelIndexTest类的testCreateHotelIndex测试方法

第五步: 验证,浏览器打开http://192.168.229.129:5601

1、删除索引库。在hotel-demo项目的HotelIndexTest类,添加如下。然后运行testDeleteHotelIndex方法
- @Test
- void testDeleteHotelIndex() throws IOException {
- DeleteIndexRequest request = new DeleteIndexRequest("hotel");
- client.indices().delete(request,RequestOptions.DEFAULT);
- }


2. 判断索引库是否存在,刚才我们已经运行过删除索引库了,现在我们来写一个测试来判断索引库是否存在
- @Test
- void testExistsHotelIndex() throws IOException {
- GetIndexRequest request = new GetIndexRequest("hotel");
- boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
- System.err.println(exists?"索引库存在":"索引库不存在");
- }

案例: 去数据库查询酒店数据,把查询到的结果导入到hotel索引库(上一节我们已经创建一个名为hotel的索引库),实现酒店数据的增删改查
简单说就是先去数据查酒店数据,把结果转换成索引库所需要的格式(新增文档的DSL语法)然后写到索引库,然后在索引库对这些酒店数据进行增删改查
第一步:在HotelIndexTest写入如下
- package cn.itcast.hotel;
-
- import cn.itcast.hotel.constants.HotelConstants;
- import cn.itcast.hotel.pojo.Hotel;
- import cn.itcast.hotel.pojo.HotelDoc;
- import cn.itcast.hotel.service.IHotelService;
- import com.alibaba.fastjson.JSON;
- import org.apache.http.HttpHost;
- import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
- import org.elasticsearch.action.delete.DeleteRequest;
- import org.elasticsearch.action.index.IndexRequest;
- import org.elasticsearch.client.RequestOptions;
- import org.elasticsearch.client.RestClient;
- import org.elasticsearch.client.RestClientBuilder;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.client.indices.CreateIndexRequest;
- import org.elasticsearch.client.indices.GetIndexRequest;
- import org.elasticsearch.common.xcontent.XContentType;
- import org.junit.jupiter.api.AfterEach;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.boot.test.context.SpringBootTest;
-
- import java.io.IOException;
-
- @SpringBootTest
- public class HotelIndexTest {
-
- private RestHighLevelClient client;
-
- @Autowired
- private IHotelService hotelService;
-
- @Test
- void init(){
- System.out.println(client);
- }
-
- @Test
- void testCreateHotelIndex() throws IOException {
- //创建Request对象
- CreateIndexRequest request = new CreateIndexRequest("hotel");
- //请求参数,MAPPING_TEMPLATE是静态常量字符串,内容是创建索引库的DSL语句
- request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
- //发起请求
- client.indices().create(request, RequestOptions.DEFAULT);
- }
-
- @Test
- void testDeleteHotelIndex() throws IOException {
- DeleteIndexRequest request = new DeleteIndexRequest("hotel");
- client.indices().delete(request,RequestOptions.DEFAULT);
- }
-
- @Test
- void testExistsHotelIndex() throws IOException {
- GetIndexRequest request = new GetIndexRequest("hotel");
- boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
- System.err.println(exists?"索引库存在":"索引库不存在");
- }
-
-
- @BeforeEach
- void setUp(){
- this.client = new RestHighLevelClient(RestClient.builder(
- //指定你Centos7部署的es的主机地址
- HttpHost.create("http://192.168.229.129:9200")
- ));
- }
-
- @AfterEach
- void tearDown() throws IOException {
- this.client.close();
- }
-
- @Test
- void testAddDocument() throws IOException {
- //根据id查询酒店数据
- //注意数据库中bigint类型对应java中的long类型
- Hotel hotel = hotelService.getById(60223L);
- //转换为文档类型
- HotelDoc hotelDoc = new HotelDoc(hotel);
- //准备Request对象
- IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
- //准备Json文档
- request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
- //发送请求
- client.index(request,RequestOptions.DEFAULT);
- }
-
- }
主要是新增这个方法
- @Test
- void testAddDocument() throws IOException {
- //根据id查询酒店数据
- //注意数据库中bigint类型对应java中的long类型
- Hotel hotel = hotelService.getById(60223L);
- //转换为文档类型
- HotelDoc hotelDoc = new HotelDoc(hotel);
- //准备Request对象
- IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
- //准备Json文档
- request.source(JSON.toJSONString(hotelDoc),XContentType.JSON);
- //发送请求
- client.index(request,RequestOptions.DEFAULT);
- }
第二步:文档新增成功,我们去浏览器查询一下

不管我们学习什么样的文档操作,java中的代码和DSL中的语句非常相似,所以我们可以类比着DSL语句来编写java代码

具体操作如下,我们查询刚才添加的id为60223的文档信息
- @Test
- void testGetDocumentById() throws IOException {
- //创建request对象
- GetRequest request = new GetRequest("hotel","60223");
- //发送请求
- GetResponse response = client.get(request,RequestOptions.DEFAULT);
- //解析结果
- String res = response.getSourceAsString();
- System.out.println(res);
- }


具体操作,把id为60223的文档信息更新一下,名字和城市
第一步:写入此方法,并运行
- @Test
- void testUpdateDocumentById() throws IOException {
- //创建Request对象
- UpdateRequest request = new UpdateRequest("hotel","60223");
- //准备参数,每两个参数为一对key value
- request.doc(
- "name","上海梅赛德斯奔驰文化中心",
- "city","阿布扎比"
- );
- //更新文档
- client.update(request,RequestOptions.DEFAULT);
- }
第二步:测试是否更新,在浏览器中Get请求

经过以上类比,我们不难写出删除文档的代码

具体操作,删除id为60223的文档信息
- @Test
- void testDeleteDocumentById() throws IOException {
- //创建Request对象
- DeleteRequest request = new DeleteRequest("hotel","60223");
- //删除文档
- client.delete(request,RequestOptions.DEFAULT);
- }
测试如下

我们一直都是操作一条id为60223的文档(相当于数据库表的某一行)。我们如何把mysql的更多数据导入进es的索引库(相当于mysql的表)呢,下面就来学习批量把文档导入进索引库
- 思路:
- 1、利用mybatis-plus把MySQL中的酒店数据查询出来
- 2、将查询到的酒店数据转换为文档类型的数据
- 3、利用RestClient中bulk批处理方法,实现批量新增文档

第一步: 在HotelDocumentTest类,添加如下
- @Test
- void testBulkRequest() throws IOException {
- //mp查出数据库中所有的信息
- List
hotelList = hotelService.list(); - //转化为hotelDoc
- List
hotelDocList = hotelList.stream() - .map(new Function
() { - @Override
- public HotelDoc apply(Hotel hotel) {
- HotelDoc hotelDoc = new HotelDoc(hotel);
- return hotelDoc;
- }
- }).collect(Collectors.toList());
- //创建Bulk请求
- BulkRequest bulkRequest = new BulkRequest();
- hotelDocList.forEach(hotelDoc -> bulkRequest
- .add(new IndexRequest("hotel").id(hotelDoc.getId().toString())
- .source(JSON.toJSONString(hotelDoc),XContentType.JSON)));
- //发送bulk请求
- client.bulk(bulkRequest, RequestOptions.DEFAULT);
- }
- }
第二步:浏览器批量查询
