JDK:1.8
SringBoot:2.1.0.RELEASE
Gardle:gradle-4.10.2
ElasticSearch:elasticsearch-6.2.4
Spring-data-elasticsearch:spring-data-elasticsearch:3.1.2.RELEASE
Java与ElasticSearch连接的两种方式:(1)使用Transport与ElasticSearch建立连接
(2)使用SpringDataElasticSearch连接连接
两种方式的优缺点:(1)优点:脱离框架,集成过程中不需要考虑与Spring的版本兼容问题,容易集成
缺点:使用原生API操作ES,代码量大,撰写困难
(2)优点:将原生API进行封装,提供了ElasticsearchRepository,操作ES非常简单,与JPA同理
缺点:出生于Spring家族,与SpringBoot,SpringData版本容易冲突
本章节使用Springboot+SpringDataElastic+gradle整合:
dependencies {
compile('org.springframework.boot:spring-boot-starter')
// 使用SpringDataElasticSearch只需要添加一处依赖即用
compile('org.springframework.boot:spring-boot-starter-data-elasticsearch')
testCompile('org.springframework.boot:spring-boot-starter-test')
// 使用lombok提供Getter与Setter,实体类只需写字段,加注释,外部类即可以通过构造器调用
annotationProcessor 'org.projectlombok:lombok:1.18.2'
compileOnly 'org.projectlombok:lombok:1.18.2'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.2'
testCompileOnly 'org.projectlombok:lombok:1.18.2'
}
spring:
data:
elasticsearch:
cluster-name: docker-cluster
cluster-nodes: 127.0.0.1:9300
repositories:
enabled: true
下载ElasticSearch,更改config目录下的elasticsearch.yml,找到cluster.name属性,值设置为SpringBoot配置文件中 cluster- name对应的值,并解除注释,否则项目启动失败!
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import javax.persistence.Id;
import java.io.Serializable;
@Data
@Document(indexName = "poms", type = "content")
public class ESDocument implements Serializable {
@Id
private String id;
@Field(analyzer = "ik_smart", searchAnalyzer = "ik_smart")
private String name;
private String projectId;
}
注:实体类需要添加@Document,项目启动会在ES中自动创建index与type,需要中文分词的字段使用@Field指定分词器名称
(前提是ES服务安装了ik分词器)
关于ElasticSearch的入门知识可以参考http://blog.51cto.com/mageedu/1714522?utm_source=tuicool&utm_medium=referral
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DocumentSearchRepository extends ElasticsearchRepository {
}
ElasticsearchRepository接口与JpaRepository同理,使用时可根据方法名称自动生成 ES Query语句,简单操作可使用该接口提供的方法(包括page,sort),简单的CRUD操作直接使用DocumentSearchRepository实例对象就可调出方法
public interface DocumentSearchService {
ESDocument getDocumentById(String id) throws WSException;
void deleteDocumentById(String id);
/**
* build add documents for the index
*
* @param ESDocuments added documents
*/
void saveDocument(List ESDocuments);
/**
* get document list by name and id order by orderField parameter
*
* @param name queried name
* @param projectId contained project id
* @param orderField order filed name
* @return document list
* @throws GTException
*/
List getDocumentsByNameOrderByCreateOn(String name,
String projectId,
String orderField)
throws WSException;
}
@Service
public class DocumentSearchServiceImpl implements DocumentSearchService {
@Autowired
private DocumentSearchRepository documentSearchRepository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Override
public ESDocument getDocumentById(String id) throws WSException {
ESDocument country = documentSearchRepository.findById(id)
.orElseThrow(() ->
new GTException(HttpStatus.NOT_FOUND,
ErrorCode.ES_REPOSITORY_DOCUMENT_NOT_EXISIS,
id));
return country;
}
@Override
public void deleteDocumentById(String id) {
documentSearchRepository.deleteById(id);
}
/**
* build add documents for the index
*
* @param ESDocuments added documents
*/
@Override
public void saveDocument(List ESDocuments) {
documentSearchRepository.saveAll(ESDocuments);
}
/**
* get document list by name and id order by orderField parameter
*
* @param name queried name
* @param projectId contained project id
* @param orderField order filed name
* @return document list
* @throws WSException
*/
@Override
public List getDocumentsByNameOrderByCreateOn(String name, String
projectId, String orderField) throws WSException {
List ESDocuments;
try {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("name", name))
.withFilter(matchPhraseQuery("projectId", projectId))
.withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
.withSort(new FieldSortBuilder(orderField).order(SortOrder.DESC))
.build();
ESDocuments = elasticsearchTemplate.queryForList(searchQuery,
ESDocument.class);
} catch (Exception e) {
throw new WSException(HttpStatus.NOT_MODIFIED,
ErrorCode.ES_REPOSITORY_FIELD_NOT_EXISTS, e);
}
return ESDocuments;
}
}
简单的查询和条件查询可以直接使用ElasticsearchRepository提供的接口,如果需要复杂的条件组合(模糊查询,完全匹配查 询,分页,排序)使用ElasticSearchTemplate实例,它一般最常用的方法是queryForList(SearchQuery query, Class
将查询条件拼接到一个SearchQuery中。这个实例不需要再任何地方创建,当项目初始化的时候已经在IOC容器中创建完成了。
使用只需DI注入即可(详情可参考DocumentSearchServiceImpl类的getDocumentsByNameOrderByCreateOn方法)。
另外是我在整合公司项目遇到的一个坑:由于公司持久化框架也是Spring-data-Jpa,而ES使用的是Spring-data-ElasticSearch,内部使用的都是CrudRepository完成CRUD的,在整合的时候两个一直冲突,解决了三天最终项目才跑起来。强烈建议将有关ES的Interface,class与JPA的Interface,class放在不同的根目录,实体类不能引用同一个,需要创建两份实体类,ES与JPA各自用各自的,否则项目跑不起来!!!
第一次写博客,哪里写的有问题的,欢迎大家提出宝贵的意见!谢谢!