Springboot中整合Spring data elasticsearch,實現相關CRUD介面
專案環境:
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' }
Java(實體-業務)程式碼如下:
實體類pojo:
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;
@Getter
@Setter
@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分詞器)
持久化dao Interface:
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DocumentSearchRepository extends ElasticsearchRepository<ESDocument,
String> {
}
ElasticsearchRepository介面與JpaRepository同理,使用時可根據方法名稱自動生成 ES Query語句,簡單操作可使用該介面提供的方法(包括page,sort),簡單的CRUD操作直接使用DocumentSearchRepository例項物件就可調出方法,
業務service Interface:
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<ESDocument> 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<ESDocument> getDocumentsByNameOrderByCreateOn(String name,
String projectId,
String orderField)
throws WSException;
}
業務service Implments class:
@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<ESDocument> 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<ESDocument> getDocumentsByNameOrderByCreateOn(String name, String
projectId, String orderField) throws WSException {
List<ESDocument> 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<T> clazz),
將查詢條件拼接到一個SearchQuery中。這個例項不需要再任何地方建立,當專案初始化的時候已經在IOC容器中建立完成了。
使用只需DI注入即可(詳情可參考DocumentSearchServiceImpl類的getDocumentsByNameOrderByCreateOn方法)。
另外是我的整合公司專案遇到的一個坑:由於公司持久化框架也是Spring-data-Jpa,內部使用的都是CrudRepository完成CRUD,在整合的時候兩個一直衝突。建議將有關ES的Interface,class與JPA的Interface,class放在不同的根目錄,實體類不能引用同一個,需要建立兩份實體類,ES與JPA各自用各自的,否則專案跑不起來!!!