在pom中添加如下依赖,现在的版本2.2.2.RELEASE对es的整合版本是6.4.3
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
<version>2.2.2.RELEASEversion>
dependency>
然后,配置application.yml
spring:
data:
elasticsearch:
cluster-name: es-cluster
cluster-nodes: 192.168.0.101:9300 # 这里注意了,sb整合es中的通讯端口是9300不是9200
通讯端口是9300不是9200
添加一个配置类,和Application启动类同级或者创建一个config的目录放置这个配置类
package com.imooc;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class ESConfig {
@PostConstruct
void init() {
System.setProperty("es.set.netty.runtime.available.processors","false");
}
如果没有配置的话,运行会报错
ERROR SpringApplication Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'elasticsearchClient' defined in class path resource [org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.elasticsearch.client.transport.TransportClient]: Factory method 'elasticsearchClient' threw exception; nested exception is java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:843)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.elasticsearch.client.transport.TransportClient]: Factory method 'elasticsearchClient' threw exception; nested exception is java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
... 42 more
Caused by: java.lang.IllegalStateException: availableProcessors is already set to [4], rejecting [4]
at io.netty.util.NettyRuntime$AvailableProcessorsHolder.setAvailableProcessors(NettyRuntime.java:51)
at io.netty.util.NettyRuntime.setAvailableProcessors(NettyRuntime.java:87)
at org.elasticsearch.transport.netty4.Netty4Utils.setAvailableProcessors(Netty4Utils.java:83)
at org.elasticsearch.transport.netty4.Netty4Transport.<init>(Netty4Transport.java:112)
at org.elasticsearch.transport.Netty4Plugin.lambda$getTransports$0(Netty4Plugin.java:86)
at org.elasticsearch.client.transport.TransportClient.buildTemplate(TransportClient.java:189)
at org.elasticsearch.client.transport.TransportClient.<init>(TransportClient.java:283)
at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:128)
at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:114)
at org.elasticsearch.transport.client.PreBuiltTransportClient.<init>(PreBuiltTransportClient.java:104)
at org.springframework.data.elasticsearch.client.TransportClientFactoryBean.buildClient(TransportClientFactoryBean.java:85)
at org.springframework.data.elasticsearch.client.TransportClientFactoryBean.afterPropertiesSet(TransportClientFactoryBean.java:80)
at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration.elasticsearchClient(ElasticsearchAutoConfiguration.java:60)
at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration$$EnhancerBySpringCGLIB$$b08b94eb.CGLIB$elasticsearchClient$0(<generated>)
at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration$$EnhancerBySpringCGLIB$$b08b94eb$$FastClassBySpringCGLIB$$3ccdc4d6.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
at org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration$$EnhancerBySpringCGLIB$$b08b94eb.elasticsearchClient(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 43 more
ERROR TestContextManager Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@632241f5] to prepare test instance [com.test.ESTest@64bba0eb]
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我们使用的是ElasticsearchTemplate
这个模版类
@Autowired
private ElasticsearchTemplate esTemplate;
假设我们现在有一个Stu的学生类和stu这个索引关联着的
package com.imooc.es.pojo;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
@Document(indexName = "stu", type = "_doc")
public class Stu {
@Id //有这个注解,es会根据这个属性值来构建_id
private Long stuId;
@Field(store = true)
private String name;
@Field(store = true)
private Integer age;
@Field(store = true)
private Float money;
@Field(store = true)
private String sign;
@Field(store = true)
private String description;
public Long getStuId() {
return stuId;
}
public void setStuId(Long stuId) {
this.stuId = stuId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Stu{" +
"stuId=" + stuId +
", name='" + name + '\'' +
", age=" + age +
", money=" + money +
", sign='" + sign + '\'' +
", description='" + description + '\'' +
'}';
}
}
public void createIndexStu() {
//创建一个Stu对象
Stu stu = new Stu();
stu.setStuId(1001L);
stu.setName("spider man");
stu.setAge(54);
stu.setMoney(1999.8f);
stu.setSign("i am spider man");
stu.setDescription("i wish i can be spider man");
//创建一个IndexQuery对象,使用其工厂类构建,使用withObject这个api来绑定一个对象,然后会根据这个对象来构建索引
IndexQuery indexQuery = new IndexQueryBuilder().withObject(stu).build();
esTemplate.index(indexQuery);
}
public void deleteIndexStu() {
//使用es的模版对象的deleteIndex来删除索引,可以传入索引名称或者其绑定的对象类
boolean flag = esTemplate.deleteIndex("stu");
System.out.println(flag);
}
public void updateStuDoc() {
//1.将要修改的字段和其修改后的值使用map来绑定,字段为key,修改值为value
Map<String, Object> sourceMap = new HashMap<>();
sourceMap.put("name", "doudou");
//2.创建indexRequest对象,需要传入一个map来定义哪些字段要改成什么值
IndexRequest indexRequest = new IndexRequest();
indexRequest.source(sourceMap);
//3.老套路,因为模版类需要一个updateQuery的对象,所以使用它的工厂类来创建,同时绑定文档的id和其对应的索引,使用withIndexRequest这个api来绑定IndexRequest对象
UpdateQuery updateQuery = new UpdateQueryBuilder()
.withId("1001")
.withClass(Stu.class)
.withIndexRequest(indexRequest).build();
esTemplate.update(updateQuery);
}
这只能一次查一个文档
public void getStuDco() {
//需要的GetQuery对象,不需要使用其工厂类来构建了,直接new出来就行了,和创建index,更新文档,删除index都不一样
GetQuery getQuery = new GetQuery();
getQuery.setId("1001");
Stu stu = esTemplate.queryForObject(getQuery, Stu.class);
System.out.println(stu);
}
public void searchStuDoc() {
Pageable pageable = PageRequest.of(0,5);
//1.使用其原生类的工厂类,withQuery这个api来绑定QueryBuilder对象来检索,但是QueryBuilder对象使用其工具类来创建,可以接分页,使用withPageable这个api
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("description","spider"))
.withPageable(pageable) //绑定分页对象
.build();
// 使用queryForPage这个api来检索,传入一个searchQuery后面加索引绑定的对象类
AggregatedPage<Stu> aggregatedPage = esTemplate.queryForPage(searchQuery, Stu.class);
List<Stu> stuList = aggregatedPage.getContent();
for(Stu stu:stuList) {
System.out.println(stuList);
}
}
这里的代码有点长,主要我们是通过SearchResultMapper
这个接口中的mapResult
方法中的SearchResponse
的对象来得到高亮的内容
public void highlightStuDoc() {
String preTag = "";
String postTag = "";
Pageable pageable = PageRequest.of(0,5);
//定义queryForPage的第一个参数:SearchQuery
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("description","spider"))
.withHighlightFields(new HighlightBuilder.Field("description")
.preTags(preTag) // 设置高亮的前标签
.postTags(postTag)) //设置高亮得到后标签
.withPageable(pageable)
.build();
//使用高亮也是模版类的queryForPage,就是后面接多个SearchResultMapper的接口
AggregatedPage<Stu> aggregatedPage = esTemplate.queryForPage(searchQuery, Stu.class, new SearchResultMapper() {
/**
*
* @param response 这个是查询后的响应结果,高亮部分可以从这里取出来
* @param clazz
* @param pageable
* @param
* @return
*/
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
System.out.println(response);
List<Stu> stuList = new ArrayList<>();
//1.和数据有关系的部分是hits部分
SearchHits hits = response.getHits();
for(SearchHit h:hits){
//获取高亮字段
HighlightField highlightField = h.getHighlightFields().get("description");
String description = highlightField.getFragments()[0].toString();
Object stuId = h.getSourceAsMap().get("stuId");
String name = (String)h.getSourceAsMap().get("name");
Integer age = (Integer)h.getSourceAsMap().get("age");
String sign = (String)h.getSourceAsMap().get("sign");
Object money = (Object)h.getSourceAsMap().get("money");
Stu stu = new Stu();
stu.setStuId(Long.valueOf(stuId.toString()));
stu.setName(name);
stu.setAge(age);
stu.setSign(sign);
stu.setMoney(Float.valueOf(money.toString()));
stu.setDescription(description);
stuList.add(stu);
}
if (stuList.size() > 0) {
return new AggregatedPageImpl<>((List<T>)stuList);
}
return null;
}
});
List<Stu> stuList = aggregatedPage.getContent();
for(Stu stu:stuList){
System.out.println(stu);
}
}
我们使用断点的方式来查看以下SearchResponse的内容
可以转换成json体来看
{
"took":5,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"_clusters":{
"total":0,
"successful":0,
"skipped":0
},
"hits":{
"total":1,
"max_score":0.2876821,
"hits":[
{
"_index":"stu",
"_type":"_doc",
"_id":"1001",
"_version":2,
"_score":0.2876821,
"_source":{
"stuId":1001,
"name":"doudou",
"age":54,
"money":1999.8,
"sign":"i am spider man",
"description":"i wish i can be spider man"
},
"highlight":{
"description":[
"i wish i can be spider man"]
}
}
]
}
}
SearchResponse的getHits方法将直接获取到第二个hits的对象内容,再从其highlight属性中可以获取标有高亮的属性和其值,直接是highlightFields[0]