很久之前就安裝了elasticsearch,一直沒用java用過,最近看了一下spring data系列的elasticsearch,這里寫一篇心得。
如果尚未安裝elasticsearch,可以 參考https://www.cnblogs.com/shaozm/p/8732842.html這篇文章。
一 、原生寫法
連接客戶端
先談談原生的寫法,
private TransportClient client; public TransportClient getClient(){ Settings setting = Settings.builder() .put("cluster.name", "elas_cluster") .put("client.transport.ignore_cluster_name", true) // .put("client.transport.nodes_sampler_interval", 5) // .put("client.transport.sniff", true) .build(); client = new PreBuiltTransportClient(setting) .addTransportAddress( new TransportAddress(new InetSocketAddress("192.168.0.2",9300)) ); return client; }
首先連接客戶端,這里單節點和集群寫法一致,如果是集群的話也只需配置master節點,官方說法是客戶端開啟嗅探之后,會把嗅探到的節點列表把本地覆蓋掉。
搜索
因為我是用spring data elasticsearch框架導入的數據,所以這里就不寫index, type的創建,就展示一下搜索的寫法。
public void search(){ QueryBuilder queryBuilder= QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("newsTitle","首個電商俱樂部")) .must(QueryBuilders.matchQuery("newsCate","科技")); SearchResponse response= client.prepareSearch("test") .setTypes("newsArticle") .setQuery(queryBuilder).get(); SearchHits searchHits = response.getHits(); for(SearchHit searchHit : searchHits) { System.out.println(searchHit); } client.close(); }
基本搜索解析
這里先談一下基本的搜索
elasticsearch 搜索請求是restful風格的,它的搜索請求都是根據 json格式的參數去搜索的。
一般來說 elasticsearch 的普通搜索json都是類似 { "query" : ... } 這樣的,
首先elasticsearch 的所有搜索基本分成兩種,一個是 過濾 ,一種是查詢 (為了區分我這里稱得分搜索) ,它們區別舉例說明
像過濾搜索判斷都是直接判斷符不符合,比如是不是這個年齡范圍的,這個字段是不是匹配的,是就返回,不是就不返回,
而得分搜索有一個score分數作為返回依據,比如這個字段匹配的,給你一點分數,那個字段沒匹配,沒分數,綜合所有的分數看是不是達標了,達標了返回,不達標不返回。
類似
{ "query" : {“range” : { ....... }} }
{ "query" : {“term” : { ....... }} } term是精確查詢,需要完全匹配
屬於過濾搜索
{ "query" : {“match” : { ....... }} }
{ "query" : {“bool” : { ....... }} }
屬於得分搜索
而像{ "query" : {“bool” : { ....... }} } 這種是組合多個查詢的,其中........ 的內容可以是多個must 或者should或者must_not或者filter的組合,最終計算score
二、spring data elasticsearch
准備工作
現在可以進入主題了,spring data elasticsearch的用法
先導包
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-elasticsearch</artifactId> <version>3.1.2.RELEASE</version> </dependency>
接着配置yml
spring:
data: elasticsearch: repositories: enabled: true cluster-nodes: 192.168.0.2:9300 cluster-name: elas_cluster
異常
這里說一個bug,如果有redis你可能會拋異常,我這里是在啟動類里配置了這么一行
public static void main(String[] args) throws Exception{ System.setProperty("es.set.netty.runtime.available.processors", "false"); SpringApplication.run(EsStart.class,args); }
使用詳解
spring-data系列的框架,用過jpa的應該都知道套路
首先配置實體注解
@Document(indexName = "test",type = "newsArticle") public class NewsArticlePO { ...... }
如果有什么字段需要分詞器,可以單獨在字段上配置
。。。。。。 @Field(type = FieldType.Text, analyzer = "ik_max_word",searchAnalyzer = "ik_max_word") private String newsTitle; 。。。。。。
這時候一啟動項目就會發現index,type已經自動生成了
第二步
創建repository
public interface ArticleRepository extends ElasticsearchRepository<NewsArticlePO,Long> { 。。。。。。 }
這里有幾種做法,一個是自己利用名字規則定義新的方法,一個是用query注解創建查詢,一個是使用父類繼承的方法。
第一種方法
在 ArticleRepository中創建方法
/** * 根據標題,類別兩個字段搜索 * */ List<NewsArticlePO> findByNewsTitleAndAndNewsCate(String newsTitle,String newsCate);
具體規則參考spring data elasticsearch的官方文檔附錄
第二種方法
在 ArticleRepository中創建方法
@Query("{\"bool\": {\"must\": [{ \"match\": { \"newsTitle\": \"?0\"}},{ \"match\": { \"newsCate\": \"?1\"}}]}}")
List<NewsArticlePO> findByQuery(String newsTitle, String newsCate);
第三種方法
在service層代碼或者其他類中注入 ArticleRepository
@Resource private ArticleRepository articleRepository;
創建方法
public Page<NewsArticlePO> searchBuild(String newsTitle, String newsCate) { QueryBuilder queryBuilder= QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("newsTitle",newsTitle)) .must(QueryBuilders.matchQuery("newsCate",newsCate)); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(queryBuilder) .build(); return articleRepository.search(searchQuery); }
這就ok了,如果不喜歡使用repository也沒事,可以注入ElasticsearchTemplate
@Resource private ElasticsearchTemplate elasticsearchTemplate; public List<NewsArticlePO> searchTemplate(String newsTitle, String newsCate){ QueryBuilder queryBuilder= QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("newsTitle",newsTitle)) .must(QueryBuilders.matchQuery("newsCate",newsCate)); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(queryBuilder) .build(); return elasticsearchTemplate.queryForList(searchQuery,NewsArticlePO.class); }
甚至可以通過elasticsearchTemplate.getClient()得到原生的client進行操作
demo項目地址 https://github.com/1160809039/elasticsearch-demo