SpringBoot从入门到精通教程(八):集成ElasticSearch
本主要介绍ElasticSearch 和 SpringBoot 的整合 ,对您有帮助的话,点个关注哦
ElastSearch 介绍
- ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。
- Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
解决了什么问题
我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作的创建是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。
具体elasticsearch相关问题可以去elastic中文社区查看。
环境准备
Java版本
:JDK8elasticsearch
: ES 6.8SpringBoot
:2.1.7.RELEASE
1.启动elasticsearch的 *.bat文件。
2.新建项目,pom文件中加入elasticsearch依赖,完整pom如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.7.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.spiritmark.boot</groupId><artifactId>ElastSearch-Boot</artifactId><version>0.0.1-SNAPSHOT</version><name>ElastSearch-Boot</name><description>elasticsearch</description><properties><java.version>1.8</java.version><testng.version>6.14.2</testng.version><spring-cloud-dependencies.version>Greenwich.RELEASE</spring-cloud-dependencies.version><kibana-logging-spring-boot-starter.version>1.2.4</kibana-logging-spring-boot-starter.version><fastjson.version>1.2.47</fastjson.version><alarm-spring-boot-starter.version>1.0.15-SNAPSHOT</alarm-spring-boot-starter.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud-dependencies.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--elasticsearch--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>${testng.version}</version><scope>test</scope></dependency><!-- 日期处理 --><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId></dependency><!--FastJson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!--feign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
application.yml 配置文件如下:
server:port: 8080servlet:context-path: /search
spring:application:name: searchdata:elasticsearch:cluster-name: my-clustercluster-nodes: localhost:9300jackson:default-property-inclusion: non_nulllogging:file: application.logpath: .level:root: infocom.spiritmark.store.client: DEBUGindex-entity:configs:- docCode: storeindexName: storetype: basedocumentPath: com.spiritmark.document.StoreDocument
spring.data.elasticsearch.cluster-name
:集群名称
spring.data.elasticsearch.cluster-nodes
:集群节点地址列表,多个节点用英文逗号(,)分隔
创建文档实体映射
创建一个实体类,然后通过注解来声明字段的映射属性。
Spring提供的注解有@Document
、@Id
、@Field
,其中@Document
作用在类,@Id
、@Field
作用在成员变量,@Id
标记一个字段作为id主键。
package com.spiritmark.boot;import com.spiritmark.document.store.*;
import com.spiritmark.search.annotation.DefinitionQuery;
import com.spiritmark.search.enums.QueryTypeEnum;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;import java.util.List;/**** @author SpiritMark* @date Create at 19:31 2019/8/22*/
@Document(indexName = "store", type = "base")
@Data
@DefinitionQuery(key = "page", type = QueryTypeEnum.IGNORE)
@DefinitionQuery(key = "size", type = QueryTypeEnum.IGNORE)
@DefinitionQuery(key = "q", type = QueryTypeEnum.FULLTEXT)
public class StoreDocument {@Id@DefinitionQuery(type = QueryTypeEnum.IN)@DefinitionQuery(key = "id", type = QueryTypeEnum.IN)@Field(type = FieldType.Keyword)private String id;/*** 基础信息*/@Field(type = FieldType.Object)private StoreBaseInfo baseInfo;/*** 标签*/@Field(type = FieldType.Nested)@DefinitionQuery(key = "tagCode", mapped = "tags.key", type = QueryTypeEnum.IN)@DefinitionQuery(key = "tagValue", mapped = "tags.value", type = QueryTypeEnum.AND)@DefinitionQuery(key = "_tagValue", mapped = "tags.value", type = QueryTypeEnum.IN)private List<StoreTags> tags;}
注解详解 :
Spring Data通过注解来声明字段的映射属性,有下面的三个注解:
- @Document 作用在类,标记实体类为文档对象,一般有两个属性
- indexName:对应索引库名称
- type:对应在索引库中的类型
- shards:分片数量,默认5
- replicas:副本数量,默认1
- @Id 作用在成员变量,标记一个字段作为id主键
- @Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:
- type:字段类型,是枚举:FieldType,可以是text、long、short、date、integer、object等
- text:存储数据时候,会自动分词,并生成索引
- keyword:存储数据时候,不会分词建立索引
- Numerical:数值类型,分两类
- 基本数据类型:long、interger、short、byte、double、float、half_float
- 浮点数的高精度类型:scaled_float
需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。 - Date:日期类型
- elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。
- index:是否索引,布尔类型,默认是true
- store:是否存储,布尔类型,默认是false
- analyzer:分词器名称,这里的ik_max_word即使用ik分词器
分析核心 类 ElasticsearchTemplate
ElasticsearchTemplate
提供了四个createIndex()
方法来创建索引,可以根据类的信息自动生成,也可以手动指定indexName和Settings
创建索引源码 :
@Override
public <T> boolean createIndex(Class<T> clazz) {return createIndexIfNotCreated(clazz);
}@Override
public boolean createIndex(String indexName) {Assert.notNull(indexName, "No index defined for Query");return client.admin().indices().create(Requests.createIndexRequest(indexName)).actionGet().isAcknowledged();
}
@Override
public boolean createIndex(String indexName, Object settings) {CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName);if (settings instanceof String) {createIndexRequestBuilder.setSettings(String.valueOf(settings), Requests.INDEX_CONTENT_TYPE);} else if (settings instanceof Map) {createIndexRequestBuilder.setSettings((Map) settings);} else if (settings instanceof XContentBuilder) {createIndexRequestBuilder.setSettings((XContentBuilder) settings);}return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
}@Override
public <T> boolean createIndex(Class<T> clazz, Object settings) {return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
}
删除索引源码
ElasticsearchTemplate
提供了2个deleteIndex()
方法来删除索引
@Override
public <T> boolean deleteIndex(Class<T> clazz) {return deleteIndex(getPersistentEntityFor(clazz).getIndexName());
}@Override
public boolean deleteIndex(String indexName) {Assert.notNull(indexName, "No index defined for delete operation");if (indexExists(indexName)) {return client.admin().indices().delete(new DeleteIndexRequest(indexName)).actionGet().isAcknowledged();}return false;
}
创建映射源码:
ElasticsearchTemplate
提供了三个putMapping()
方法来创建映射
@Override
public <T> boolean putMapping(Class<T> clazz) {if (clazz.isAnnotationPresent(Mapping.class)) {String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();if (!StringUtils.isEmpty(mappingPath)) {String mappings = readFileFromClasspath(mappingPath);if (!StringUtils.isEmpty(mappings)) {return putMapping(clazz, mappings);}} else {LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");}}ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);XContentBuilder xContentBuilder = null;try {ElasticsearchPersistentProperty property = persistentEntity.getRequiredIdProperty();xContentBuilder = buildMapping(clazz, persistentEntity.getIndexType(),property.getFieldName(), persistentEntity.getParentType());} catch (Exception e) {throw new ElasticsearchException("Failed to build mapping for " + clazz.getSimpleName(), e);}return putMapping(clazz, xContentBuilder);
}@Override
public <T> boolean putMapping(Class<T> clazz, Object mapping) {return putMapping(getPersistentEntityFor(clazz).getIndexName(), getPersistentEntityFor(clazz).getIndexType(),mapping);
}@Override
public boolean putMapping(String indexName, String type, Object mapping) {Assert.notNull(indexName, "No index defined for putMapping()");Assert.notNull(type, "No type defined for putMapping()");PutMappingRequestBuilder requestBuilder = client.admin().indices().preparePutMapping(indexName).setType(type);if (mapping instanceof String) {requestBuilder.setSource(String.valueOf(mapping), XContentType.JSON);} else if (mapping instanceof Map) {requestBuilder.setSource((Map) mapping);} else if (mapping instanceof XContentBuilder) {requestBuilder.setSource((XContentBuilder) mapping);}return requestBuilder.execute().actionGet().isAcknowledged();
}
测试
@Test
public void testCreate() {System.out.println(elasticsearchTemplate.createIndex(StoreDocument.class));System.out.println(elasticsearchTemplate.putMapping(StoreDocument.class));
}
Repository 接口
另一种则是通过Repository接口。Spring提供的ES的Repository接口为
ElasticsearchCrudRepository
,所以我们就可以直接定义额新的接口,然后实现ElasticsearchCrudRepository
即可:
package com.spiritmark.boot;import com.taoche.document.StoreDocument;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;/*** 门店Repository* @author 李锋镝* @date Create at 09:30 2019/8/23*/
public interface StoreRepository extends ElasticsearchRepository<StoreDocument, String> { }
测试
@Test
public void testSave() {StoreDocument storeDocument = new StoreDocument();storeDocument.setId("1");StoreBaseInfo baseInfo = new StoreBaseInfo();baseInfo.setStoreId("1");baseInfo.setCreatedTime(DateTime.now());storeDocument.setBaseInfo(baseInfo);storeRepository.save(storeDocument);
}
查询
ES的主要功能就是查询,
ElasticsearchRepository
也提供了基本的查询接口,比如findById()、findAll()、findAllById()、search()等方法;当然也可以使用Spring Data提供的另外一个功能:Spring Data JPA——通过方法名创建查询,当然需要遵循一定的规则,比如你的方法名叫做findByTitle(),那么它就知道你是根据title查询,然后自动帮你完成,这里就不仔细说了。
上边说的基本能满足一般的查询,复杂一点的查询就无能为力了,这就需要用到自定义查询,这里可以查看我的另一篇博客SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询,这里边有详细的说明。
SpringBoot从入门到精通教程(八):集成ElasticSearch相关推荐
- SpringBoot从入门到精通教程(二十九)- 微信企业支付集成(五分钟集成)
需求背景 SpringBoot用法:微信企业支付集成(五分钟集成) 问题痛点 通过SpringBoot框架,集成服务端微信企业支付接口,做到下载即用(填写好相关微信支付后台相关Key信息),最快五分钟 ...
- SpringBoot从入门到精通教程(三十一)- 爬虫框架集成
需求背景 SpringBoot用法:爬虫框架集成 业务场景 以抓取"今日头条"新闻举例说明 技术点 1. 集成爬虫框架webmagic(更多了解webmagic,可以去官方地址) ...
- SpringBoot从入门到精通教程(二十七)- @Valid注解用法详解+全局处理器Exception优雅处理参数验证用法
问题痛点 用 Spring 框架写代码时,写接口类,相信大家对该类的写法非常熟悉.在写接口时要写效验请求参数逻辑,这时候我们会常用做法是写大量的 if 与 if else 类似这样的代码来做判断,如下 ...
- SpringBoot从入门到精通教程
SpringBoot从入门到精通教程 一.来自ImportNew公众号的SpringBoot教程系列,可参考学习 SpringBoot (一) :入门篇--http://mp.weixin.qq.co ...
- SpringBoot从入门到精通教程(七):集成Redis
今天,我们继续讲SpringBoot整合Redis ,也就缓存,它将与我们的Springboot整合 Redis 简介 Redis 是当前比较热门的NOSQL系统之一,它是一个开源的使用ANSI c语 ...
- Elasticsearch入门到精通教程 - 学习资料综合
背景 因经常被问到Elasticsearch相关一些资料教程,这里特例整理一份以前自己的学习资料,希望对你有用. 信息资料 1. 基本API用法教程 Elasticsearch JAVA API教程G ...
- SpringCloud从入门到精通教程/SpringCloud Alibaba从入门到精通教程
对于SpringCloud,很多小伙伴问到了我的研究学习资料来源,除官方文档外,特例完整整理一下自己的平时参考学习其他资料,以及分享实战项目源码和代码资源,供大家参考学习 主要教程:SpringClo ...
- Arduino Mixly入门到精通教程
目录 1.介绍 2.实验器材和相关资料下载链接 3. Uno Plus 开发板和米思齐软件 第1小节 简单介绍 Uno Plus 开发板 第2小节 Uno Plus 开发板的驱动安装方法 第3小节 ...
- C 语言从入门到精通教程(2021 )
C 语言从入门到精通教程(2021年) 文章目录 计算机常识 什么是计算机程序 ? 什么是计算机语言 ? 常见的计算机语言类型有哪些 ? 什么是C语言? C语言历史 C语言标准 C语言现状 为什么要学 ...
最新文章
- [LeetCode]题解(python):019-Remove Nth Node From End of List
- 王勇DRP项目浏览器无法正常显示问题
- hj212协议如何和php通讯,HJ212数据传输标准报文解析
- [攻防世界 pwn]——time_formatter(内涵peak小知识)
- 计算机辅助教育会议,子会议1:学习科学、计算机辅助合作学习、智慧教育
- python循环结束执行后面代码_计算机程序中某种代码的反复执行,称为________。Python中的循环有重复一定次数的________,也有重复到某种情况结束的________。...
- cookie 百科_cookie是什么
- 烂泥:利用Diskgen找回分区破坏前的资料
- 我是如何用6个月,从0编程经验变成数据科学家的?
- c语言链表贪吃蛇脚本之家,C++控制台实现贪吃蛇游戏
- 年夜饭之 -- 洋葱炒墨鱼仔
- 人性的弱点---第三篇---得人同意于你的十二种方法3
- 以太坊 智能合约 代码 数据空间 存储在哪儿
- Unity官方案例精讲_2015_优化
- pdf reference官方指南之-图片
- 综合布线(楼栋)需求分析报告
- 开发工具-Hijson
- cdrx4自动排版步骤_Coreldraw插件emboss使用方法 CDRX4的自动排版插件 百分之百显示问题...
- 救生艇(双指针)-C语言
- 10 令牌颁发 OAuth2TokenEndpointFilter