SpringBoot整合Elasticsearch实现索引和文档的操作方法

网友投稿 486 2023-01-20

SpringBoot整合Elasticsearch实现索引和文档的操作方法

SpringBoot整合Elasticsearch实现索引和文档的操作方法

Elasticsearch 是一个分布式、可扩展、近实时的高性能搜索与数据分析引擎。Elasticsearch 基于 Apache Lucene 构建,采用 java 编写,并使用 Lucene 构建索引、提供搜索功能。Elasticsearch 的目标是让全文搜索功能的落地变得简单。

本文是SpringBoot整合Elasticsearch与综合实例的第一篇,主要实现SpringBoot整合Elasticsearch实现索引和文档的相关操作。

1、SpringBoot整合Elasticsearch的步骤

(1)创建SpringBoot项目,项目结构如下图:

(2)使用Maven添加依赖文件

在pom.xml配置信息文件中,添加 Elasticsearch服务、Elasticsearch高级客户端的依赖:

org.elasticsearch

elasticsearch

7.11.1

org.elasticsearch.client

elasticsearch-rest-high-level-client

7.11.1

(3)Elasticsearch的配置

在 application.yml 配置文件中配置 Elasticsearch 信息:

# Elasticsearch配置

elasticsearch:

hostname: 127.0.0.1

port: 9200

scheme: http

(4)Elasticsearch配置类(config层)

创建 com.pjb.config 包,并创建 ElasticsearchConfig 类(Elasticsearch配置类),并使用 @Configuration 注解,标注该类为配置类。

package com.pjb.config;

import org.apache.http.HttpHost;

import org.elasticsearch.client.RestClient;

import org.elasticsearch.client.RestClientBuilder;

import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

/**

* Elasticsearch配置类

* @author pan_junbiao

**/

@Configuration

public class ElasticsearchConfig

{

@Value("${elasticsearch.hostname}")

private String hostname;

@Value("${elasticsearch.port}")

private int port;

@Value("${elasticsearch.scheme}")

private String scheme;

/**

* 初始化:高级客户端

* @return

*/

@Bean

public RestHighLevelClient restHighLevelClient()

{

RestHighLevelClient restHighLevelClient = null;

try

{

RestClientBuilder builder = RestClient.builder(new HttpHost(hostname, port, scheme));

restHighLevelClient = new RestHighLevelClient(builder);

return restHighLevelClient;

}

catch (Exception ex)

{

System.out.println("初始化Elasticsearch高级客户端失败");

ex.printStackTrace();

}

return restHighLevelClient;

}

}

2、索引的操作

在 Elasticsearch 中开始为数据建立索引之前要做的第一步操作是创建——我们的数据主要容器。这里的索引类似于 SQL 中的数据库概念。它是类型(相当于 SQL 中的表)和文档(相当于 SQL 中的记录)的容器。

存储数据的行为叫作索引。在 Elasticsearch 中,文档会归属于一种类型,这些类型会存在于索引中。

Elasticsearch 集群和数据库中核心概念的对应关系如下:

Elasticsearch 集群

关系型数据库

索引

数据库

类型

文档

行数据

字段

列数据

定义一个博客信息(blog_info)的数据表结构:

字段

类型

说明

blogId

long

博客ID

blogName

text

博客名称

blogUrl

keyword

博客地址

blogPoints

double

博客积分

createDate

date

创建时间

blogDescribe

text

博客描述

字段类型必须映射到 Elasticsearch 的基本类型之一,并且需要添加有关如何索引字段的选项。

推荐本博客文章1:《Elasticsearch映射类型》

推荐本博客文章2:《Elasticsearch基本操作》

Elasticsearch教程:《Elasticsearch教程》

创建 com.pjb.entity 包,并创建BlogInfo类(博客信息实体类)。

package com.pjb.entity;

import java.util.Date;

/**

* 博客信息实体类

* @author pan_junbiao

**/

public class BlogInfo

{

private int blogId; //博客ID

private String blogName; //博客名称

private String blogUrl; //博客地址

private double blogPoints; //博客积分

private Date createDate; //创建时间

private String blogDescribe; //博客描述

//构建方法1

public BlogInfo()

{

}

//构建方法2

public BlogInfo(int blogId, String blogeAJLBName, String blogUrl, double blogPoints, Date createDate, String blogDescribe)

{

this.blogId = blogId;

this.blogName = blogName;

this.blogUrl = blogUrl;

this.blogPoints = blogPoints;

this.createDate = createDate;

this.blogDescribe = blogDescribe;

}

public int getBlogId()

{

return blogId;

}

public void setBlogId(int blogId)

{

this.blogId = blogId;

}

public String getBlogName()

{

return blogName;

}

public void setBlogName(String blogName)

{

this.blogName = blogName;

}

public String getBlogUrl()

{

return blogUrl;

}

public void setBlogUrl(String blogUrl)

{

this.blogUrl = blogUrl;

}

public double getBlogPoints()

{

return blogPoints;

}

public void setBlogPoints(double blogPoints)

{

this.blogPoints = blogPoints;

}

public Date getCreateDate()

{

return createDate;

}

public void setCreateDate(Date createDate)

{

this.createDate = createDate;

}

public String getBlogDescribe()

{

return blogDescribe;

}

public void setBlogDescribe(String blogDescribe)

{

this.blogDescribe = blogDescribe;

}

}

2.1 索引存在验证

(1)编写索引存在验证方法:

/**

* Elasticsearch高级客户端

*/

@Autowired

private RestHighLevelClient restHighLevelClient;

/**

* 索引存在验证

* @param indexName 索引名称

*/

@Override

public boolean existsIndex(String indexName)

{

boolean exists = false;

//参数验证

if(indexName==null || indexName.length()<=0)

{

return false;

}

try

{

//构建索引存在验证请求

GetIndexRequest request = new GetIndexRequest(indexName);

//执行请求

exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

}

catch (Exception ex)

{

ex.printStackTrace();

}

return exists;

}

2.2  创建索引

(1)编写创建索引方法:

/**

* Elasticsearch高级客户端

*/

@Autowired

private RestHighLevelClient restHighLevelClient;

/**

* 创建索引

* @param indexName 索引名称

*/

@Override

public boolean createIndex(String indexName)

{

boolean result = false;

//参数验证

if(indexName==null || indexName.length()<=0)

{

return false;

}

try

{

//1.创建索引的请求

CreateIndexRequest request = new CreateIndexRequest(indexName);

//构建索引结构

XContentBuilder builder = XContentFactory.jsonBuilder();

builder.startObject();

{

builder.startObject("properties");

{

//创建博客ID文档字段

builder.startObject("blogId");

{

builder.field("type", "long");

}

builder.endObject();

//创建博客名称文档字段

builder.startObject("blogName");

{

builder.field("type", "text");

}

builder.endObject();

//创建博客地址文档字段

builder.startObject("blogUrl");

{

builder.field("type", "keyword");

}

builder.endObject();

//创建博客积分字段

builder.startObject("blogPoints");

{

builder.field("type", "double");

}

builder.endObject();

//创建创建时间字段

builder.startObject("createDate");

{

builder.field("type", "date");

}

builder.endObject();

//创建博客描述字段

builder.startObject("blogDescribe");

{

builder.field("type", "text")

//插入时分词

.field("analyzer", "ik_smart")

//搜索时分词

.field("search_analyzer", "ik_max_word");

}

builder.endObject();

}

builder.endObject();

}

builder.endObject();

request.mapping(builder);

//2客户端执行请求,请求后获得响应

CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

result = true;

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

package com.pjb;

import com.pjb.entity.BlogInfo;

import com.pjb.service.impl.BlogService;

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.test.context.SpringBootTest;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

/**

* 博客服务测试类

* @author pan_junbiao

**/

@SpringBootTest

public class BlogServiceTest

{

@BeforeEach

private void setUp()

{

}

@AfterEach

private void tearDown()

{

}

/**

* 博客业务逻辑类

*/

@Autowired

private BlogService blogService;

/**

* 索引名称

* 注意:索引名称必须小写

*/

private String _indexName = "blog_info";

/**

* 测试:创建索引

* @author pan_junbiao

*/

@Test

public void createIndex()

{

//判断索引是否存在

boolean exists = blogService.existsIndex(_indexName);

if(exists)

{

System.out.println("索引已经存在");

return;

}

//创建索引

boolean result = blogService.createIndex(_indexName);

if(result)

{

System.out.println("索引创建成功");

}

else

{

System.out.println("索引创建失败");

}

}

}

(4)使用 ElasticSearch-head 插件查看执行结果:

2.3 删除索引

(1)编写删除索引方法:

/**

* 删除索引

* @param indexName 索引名称

*/

@Override

public boolean deleteIndex(String indexName)

{

boolean result = false;

//参数验证

if(indexName==null || indexName.length()<=0)

{

return false;

}

//注意:删除索引前,必须先判断索引是否存在,否则会报异常

if(!existsIndex(indexName))

{

//该索引不存在

return false;

}

try

{

//创建删除索引请求

DeleteIndexRequest request = new DeleteIndexRequest(indexName);

//执行请求返回响应结果

AcknowledgedResponse deleteIndexResponse = restHighLevelClient.indices().delete(request,RequestOptions.DEFAULT);

//解析响应结果

result = deleteIndexResponse.isAcknowledged();

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

/**

* 测试:删除索引

* @author pan_junbiao

*/

@Test

public void deleteIndex()

{

//删除索引

boolean result = blogService.deleteIndex(_indexName);

if(result)

{

System.out.println("删除索引成功");

}

else

{

System.out.println("删除索引失败");

}

//判断索引是否存在

boolean exists = blogService.existsIndex(_indexName);

if(exists)

{

System.out.println("索引存在");

}

else

{

System.out.println("索引不存在");

}

}

(3)通过控制器查看执行结果:

3、文档的操作

创建文档表示将一个或多个文档存储在索引中,这与在关系型数据库中插入记录的概念是类似的。

在 Elasticsearch 的核心引擎 Lucene 中,插入或更新文档的成本是相同的:在 Lucene 和 Elasticsearch 中,更新意味着替换。

3.1 新增文档

(1)编写新增文档方法:

/**

* 新增文档

* @param indexName 索引名称

* @param documentId 文档ID

* @param blogInfo 博客实体类

*/

@Override

public boolean addDocument(String indexName, String documentId, BlogInfo blogInfo)

{

boolean result = false;

try

{

//将博客信息实体类转换为Map格式

Map blogMap = toBlogMap(blogInfo);

//1、构建新增文档请求

IndexRequest request = new IndexRequest(indexName).id(documentId).source(blogMap);

//2、执行请求,返回响应结果

IndexResponse response = restHighLevelClient.index(request,RequestOptions.DEFAULT);

result = true;

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

/**

* 将博客信息实体类转换为Map格式

*/

private Map toBlogMap(BlogInfo blogInfo)

{

Map blogMap = new HashMap<>();

blogMap.put("blogId", blogInfo.getBlogId());

blogMap.put("blogName", blogInfo.getBlogName());

blogMap.put("blogUrl", blogInfo.getBlogUrl());

blogMap.put("blogPoints", blogInfo.getBlogPoints());

blogMap.put("createDate", blogInfo.getCreateDate());

blogMap.put("blogDescribe", blogInfo.getBlogDescribe());

return blogMap;

}

(2)编写测试方法:

/**

* 测试:新增文档

* @author pan_junbiao

*/

@Test

public void addDocument()

{

//创建博客实体类

BlogInfo blogInfo = new BlogInfo();

blogInfo.setBlogId(1);

blogInfo.setBlogName("pan_junbiao的博客");

blogInfo.setBlogUrl("https://blog.csdn-/pan_junbiao");

blogInfo.setBlogPoints(120.68);

blogInfo.setCreateDate(new Date());

blogInfo.setBlogDescribe("您好,欢迎访问 pan_junbiao的博客");

//文档ID(根据业务,我们以博客ID作为文档ID)

String documentId = String.valueOf(blogInfo.getBlogId());

//新增文档

boolean result = blogService.addDocument(_indexName, documentId, blogInfo);

if(result)

{

System.out.println("新增文档成功");

}

else

{

System.out.println("新增文档失败");

}

}

(3)使用Kibana工具查看执行结果:

Elasticsearch查询命令:GET /blog_info/_doc/1

3.2 批量新增文档

(1)编写批量新增文档方法:

/**

* 批量新增文档

* @param indexName 索引名称

* @param blogList 博客列表

*/

@Override

public boolean addBulkDocument(String indexName, List blogList)

{

boolean result = false;

try

{

//1、构建批量请求

BulkRequest request = new BulkRequest();

//遍历博客列表,添加批量请求

for(BlogInfo blogInfo : blogList)

{

//将博客信息实体类转换为Map格式

Map blogMap = toBlogMap(blogInfo);

//文档ID(根据业务,我们以博客ID作为文档ID)

String documentId = String.valueOf(blogInfo.getBlogId());

//加入请求

request.add(new IndexRequest(indexName).id(documentId).source(blogMap));

}

//执行批量请求

BulkResponse bulkItemResponses = restHighLevelClient.bulk(request,RequestOptions.DEFAULT);

result = true;

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

/**

* 测试:批量新增文档

* @author pan_junbiao

*/

@Test

public void addBulkDocument()

{

//创建博客实体列表

List blogInfoList = new ArrayList<>();

blogInfoList.add(new BlogInfo(1,"pan_junbiao的博客","https://blog.csdn-/pan_junbiao",120.68,new Date(),"您好,欢迎访问 pan_junbiao的博客"));

blogInfoList.add(new BlogInfo(2,"pan_junbiao的博客","https://blog.csdn-/pan_junbiao",85.12,new Date(),"您好,欢迎访问 pan_junbiao的博客"));

blogInfoList.add(new BlogInfo(3,"pan_junbiao的博客","https://blog.csdn-/pan_junbiao",94.37,new Date(),"您好,欢迎访问 pan_junbiao的博客"));

blogInfoList.add(new BlogInfo(4,"pan_junbiao的博客","https://blog.csdn-/pan_junbiao",365.19,new Date(),"您好,欢迎访问 pan_junbiao的博客"));

blogInfoList.add(new BlogInfo(5,"pan_junbiao的博客","https://blog.csdn-/pan_junbiao",287.33,new Date(),"您好,欢迎访问 pan_junbiao的博客"));

//批量新增文档

boolean result = blogService.addBulkDocument(_indexName, blogInfoList);

if(result)

{

System.out.println("批量新增文档成功");

}

else

{

System.out.println("批量新增文档失败");

}

}

(3)使用 ElasticSearch-head 插件查看执行结果:

3.3 修改文档

(1)编写修改文档方法:

/**

* 修改文档

* @param indexName 索引名称

* @param documentId 文档ID

* @param blogInfo 博客实体类

*/

@Override

public boolean updateDocument(String indexName, String documentId, BlogInfo blogInfo)

{

boolean result = false;

try

{

//将博客信息实体类转换为Map格式

Map blogMap = toBlogMap(blogInfo);

//1、构建更新文档请求

UpdateRequest request = new UpdateRequest(indexName,documentId).doc(blogMap);

//2、执行请求,返回响应结果

UpdateResponse response = restHighLevelClient.update(request,RequestOptions.DEFAULT);

result = true;

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

/**

* 测试:修改文档

* @author pan_junbiao

*/

@Test

public void updateDocument()

{

//创建博客实体类

BlogInfo blogInfo = new BlogInfo();

blogInfo.setBlogId(2);

blogInfo.setBlogName("pan_junbiao的博客_002");

blogInfo.setBlogUrl("https://blog.csdn-/pan_junbiao");

blogInfo.setBlogPoints(120.68);

blogInfo.setCreateDate(new Date());

blogInfo.setBlogDescribe("您好,欢迎访问 pan_junbiao的博客_002");

//文档ID(根据业务,我们以博客ID作为文档ID)

String documentId = String.valueOf(blogInfo.getBlogId());

//新增文档

boolean result = blogService.updateDocument(_indexName, documentId, blogInfo);

if(result)

{

System.out.println("修改文档成功");

}

else

{

System.out.println("修改文档失败");

}

}

(3)使用Kibana工具查看执行结果:

Elasticsearch查询命令:GET /blog_info/_doc/2

3.4 删除文档

(1)编写删除文档方法:

/**

* 删除文档

* @param indexName 索引名称

* @param documentId 文档ID

*/

@Override

public boolean deleteDocument(String indexName, String documentId)

{

boolean result = false;

try

{

//1、构建删除文档请求

DeleteRequest request = new DeleteRequest(indexName,documentId);

//2、执行删除请求,返回响应结果

DeleteResponse deleteResponse = restHighLevelClient.delete(request,RequestOptions.DEFAULT);

result = true;

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

/**

* 测试:删除文档

* @author pan_junbiao

*/

@Test

public void deleteDocument()

{

//删除文档ID为3的文档信息

String documentId = "3";

boolean result = blogService.deleteDocument(_indexName, documentId);

if(result)

{

System.out.println("修改文档成功");

}

else

{

System.out.println("修改文档失败");

}

}

(3)使用Kibana工具查看执行结果:

Elasticsearch查询命令:GET /blog_info/_doc/3

3.5 判断文档是否存在

(1)编写判断文档是否存在方法:

/**

* 判断文档是否存在

* @param indexName 索引名称

* @param documentId 文档ID

*/

@Override

public boolean existsDocument(String indexName, String documentId)

{

boolean result = false;

try

{

//1、构建请求

GetRequest getRequest = new GetRequest(indexName, documentId);

//禁用提取源

getRequest.fetchSourceContext(new FetchSourceContext(false));

//禁用提取存储字段

getRequest.storedFields("_none_");

//2、执行请求,返回结果

result = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

/**

* 测试:判断文档是否存在

* @author pan_junbiao

*/

@Test

public void existsDocument()

{

//判断文档ID为3的文档是否存在

String documentId = "3";

boolean result = blogService.existsDocument(_indexName, documentId);

if(result)

{

System.out.println("文档存在");

}

else

{

System.out.println("文档不存在");

}

}

(3)通过控制器查看执行结果:

3.6 获取文档

(1)编写获取文档方法:

/**

* 获取文档

* @param indexName 索引名称

* @param documentId 文档ID

* @param beanType 返回结果的类型

*/

@Override

public T getDocumentToBean(String indexName, String documentId, Class beanType)

{

T result = null;

try

{

//1、构建请求

GetRequest getRequest = new GetRequest(indexName, documentId);

//2、执行请求,返回响应结果

GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);

//3、解析响应结果

if (getResponse != null)

{

//获取JSON结果

String jsonString = getResponse.getSourceAsString();

//使用Jackson工具,将JSON转换为实体类

ObjectMapper mapper = new ObjectMapper();

result = mapper.readValue(jsonString, beanType);

}

}

catch (Exception ex)

{

ex.printStackTrace();

}

return result;

}

(2)编写测试方法:

/**

* 测试:获取文档

* @author pan_junbiao

*/

@Test

public void getDocumentToBean() throws Exception

{

//判断文档ID为1的文档信息

String documentId = "1";

BlogInfo blogInfo = blogService.getDocumentToBean(_indexName, documentId,BlogInfo.class);

//打印信息

if(blogInfo!=null)

{

System.out.println("博客ID:" + blogInfo.getBlogId());

System.out.println("博客名称:" + blogInfo.getBlogName());

System.out.println("博客地址:" + blogInfo.getBlogUrl());

System.out.println("博客积分:" + blogInfo.getBlogPoints());

System.out.println("创建时间:" + blogInfo.getCreateDate());

System.out.println("博客描述:" + blogInfo.getBlogDescribe());

}

}

(3)通过控制器查看执行结果:

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:app和小程序统一(app和小程序统一开发)
下一篇:h5跳转小程序(h5跳转小程序怎么做)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~