SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码)
准备工作
环境准备
java版本
java version "1.8.0_121" java(tm) se runtime environment (build 1.8.0_121-b13) java hotspot(tm) 64-bit server vm (build 25.121-b13, mixed mode)
es版本
{ "name": "pyafjhz", "cluster_name": "my-cluster", "cluster_uuid": "oc28y-cnqdugitc7qq5w8w", "version": { "number": "6.8.2", "build_flavor": "oss", "build_type": "tar", "build_hash": "b506955", "build_date": "2019-07-24t15:24:41.545295z", "build_snapshot": false, "lucene_version": "7.7.0", "minimum_wire_compatibility_version": "5.6.0", "minimum_index_compatibility_version": "5.0.0" }, "tagline": "you know, for search" }
springboot版本
2.1.7.release
开发工具使用的是idea
安装es
elasticsearch介绍以及安装:elasticsearch入门-基本概念介绍以及安装
开始
创建springboot项目
打开idea,在菜单中点击
file
>new
>project...
在弹框中选择spring initializr
然后next
- 填写项目名等,然后
next
,
选择依赖的jar包(一般我只选lombok,其他的自己手动加),然后
next
。最后选择项目所在路径,点击
finish
。
搞定收工。至此,一个新的springboot项目就新鲜出炉了。
pom文件
当然,具体依赖的jar包肯定不止第2步选择的那些,其中springboot提供的操作es的jar包spring-boot-starter-data-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.lifengdi</groupid> <artifactid>search</artifactid> <version>0.0.1-snapshot</version> <name>search</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文件
application.yml文件配置如下:
server: port: 8080 servlet: context-path: /search spring: application: name: search data: elasticsearch: cluster-name: my-cluster cluster-nodes: localhost:9300 jackson: default-property-inclusion: non_null logging: file: application.log path: . level: root: info com.lifengdi.store.client: debug index-entity: configs: - doccode: store indexname: store type: base documentpath: com.lifengdi.document.storedocument
spring.data.elasticsearch.cluster-name
:集群名称
spring.data.elasticsearch.cluster-nodes
:集群节点地址列表,多个节点用英文逗号(,)分隔
创建es文档和映射
首先创建一个java对象,然后通过注解来声明字段的映射属性。
spring提供的注解有@document
、@id
、@field
,其中@document
作用在类,@id
、@field
作用在成员变量,@id
标记一个字段作为id主键。
package com.lifengdi.document; import com.lifengdi.document.store.*; import com.lifengdi.search.annotation.definitionquery; import com.lifengdi.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; /** * 门店document * * @author 李锋镝 * @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; }
创建索引
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
提供了三个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)); }
删除索引
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; }
新增&修改文档
在elasticsearch中文档是不可改变的,不能修改它们。相反,如果想要更新现有的文档,需要重建索引或者进行替换。
所以可以使用和新增同样的接口来对文档进行修改操作。区分的依据就是id。
下面提供新增&修改文档的其中两种方法,一种是通过elasticsearchtemplate
提供的index()
方法:
@override public string index(indexquery query) { string documentid = prepareindex(query).execute().actionget().getid(); // we should call this because we are not going through a mapper. if (query.getobject() != null) { setpersistententityid(query.getobject(), documentid); } return documentid; }
示例代码如下:
/** * 更新索引 * @param indexname 索引名称 * @param type 索引类型 * @param id id * @param jsondoc json格式的文档 * @param refresh 是否刷新索引 * @return id */ public string index(string indexname, string type, string id, jsonnode jsondoc, boolean refresh) throws jsonprocessingexception { log.info("abstractdocumentindexservice更新索引.indexname:{},type:{},id:{},jsondoc:{}", indexname, type, id, jsondoc); indexquery indexquery = new indexquerybuilder() .withindexname(indexname) .withtype(type) .withid(id) .withsource(objectmapper.writevalueasstring(jsondoc)) .build(); try { if (elasticsearchtemplate.indexexists(indexname)) { string index = elasticsearchtemplate.index(indexquery); if (refresh) { elasticsearchtemplate.refresh(indexname); } return index; } } catch (exception e) { log.error("更新索引失败,刷新es重试", e); elasticsearchtemplate.refresh(indexname); return elasticsearchtemplate.index(indexquery); } throw baseexception.index_not_exists_exception.build(); }
另一种则是通过repository接口。spring提供的es的repository接口为elasticsearchcrudrepository
,所以我们就可以直接定义额新的接口,然后实现elasticsearchcrudrepository
即可:
package com.taoche.docindex.repo; 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查询语句,实现多条件的复杂查询,这里边有详细的说明。
另外还有一个比较厉害的功能,elasticsearch的聚合;聚合主要实现的是对数据的统计、分析。这个暂时没有用到的,所以要看聚合功能的小伙伴们可能要失望了~ 哈哈哈~~~
聚合功能以后有时间会再单独说的~都会有的。
至此,springboot整合elasticsearch基本结束,有什么不明白的地方请留言~
源码
git项目地址:
如果觉得有帮助的话,请帮忙点赞、点星小小的支持一下~
谢谢~~
原文链接:
上一篇: 饭店的服务员的话术