Spring?Data?Elasticsearch使用方式(Elasticsearch)
1. 項目部署
1.1 添加依賴
在項目的 pom.xml 中引?Spring Data Elasticsearch的啟動器。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
1.2 配置application.yml 文件
spring:
data:
elasticsearch:
cluster-name: csdn-elastic
cluster-nodes: 127.0.0.1:9301,127.0.0.1:9302,127.0.0.1:9303需要注意的是,Spring Data Elasticsearch底層使?的不是Elasticsearch提供的RestHighLevelClient,?是 TransportClient,并不采?HTTP協(xié)議通信,?是訪問Elasticsearch對外開放的TCP端?。
我們在之前集群配置 中,設(shè)置的端?分別是:9301、9302、9303。
1.3 測試是否注入成功
在test測試?件夾下的com.csdn.es包下創(chuàng)建?個SpringDataESTests測試類。通過@Autowired注解對 ElasticsearchTemplate進?注?,測試對象是否可以獲取到。
package com.csdn.es;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringDataESTests {
@Autowired
private ElasticsearchTemplate template;
@Test
public void check() {
System.err.println(template);
}
}注: 使用 Spring Data Elasticsearch 是springboot 版本不能太高,建議使用 2.1.6.RELEASE 版本。如果有 Rest Client 版本太高也會注入失敗,建議使用 6.4.3 。
2. 操作
2.1 索引庫操作
2.1.1 實體類注解
1.我們在Product實體類上添加下?的?些注解。
package com.csdn.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
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;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "csdn", type = "product", shards = 3, replicas = 1)
public class Product {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title; // 標(biāo)題
@Field(type = FieldType.Keyword)
private String category; // 分類
@Field(type = FieldType.Keyword)
private String brand; // 品牌
@Field(type = FieldType.Double)
private Double price; // 價格
@Field(type = FieldType.Keyword, index = false)
private String images; // 圖?地址
}
2.在SpringDataESTests類中定義創(chuàng)建索引的createIndex()?法。
@Test
public void createIndex() {
// 創(chuàng)建索引庫,并制定實體類的字節(jié)碼
template.createIndex(Product.class);
}2.1.2 創(chuàng)建映射
剛才的注解已經(jīng)把映射關(guān)系也配置上了,所以創(chuàng)建映射只需要這樣:
@Test
public void createMapping() {
template.putMapping(Product.class);
}2.2 索引數(shù)據(jù)CRUD操作
SDE的索引數(shù)據(jù)CRUD操作并沒有封裝在ElasticsearchTemplate類中,?是有?個叫做ElasticsearchRepository的 接?中。
在com.csdn.respository包下?定義ProductRepository接?,并繼承ElasticsearchRespository接?。
package com.csdn.respository;
import com.yx.pojo.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface ProductRepository extends ElasticsearchRepository<Product, Long> {
}2.2.1 創(chuàng)建索引數(shù)據(jù)
1.先來看單個創(chuàng)建。在SpringDataESTests類中定義addDocument()?法。
@Autowired
private ProductRepository productRepository;
@Test
public void addDocument() {
Product product = new Product(1L, "???機Mix", "?機", "??", 2899.00,
"http://image.yx.com/12479122.jpg");
// 添加索引數(shù)據(jù)
productRepository.save(product);
}2.再來看批量創(chuàng)建。在SpringDataESTests類中定義addDocuments()?法。
@Test
public void addDocuments() {
// 準(zhǔn)備?檔數(shù)據(jù)
List<Product> list = new ArrayList<>();
list.add(new Product(2L, "堅果?機R1", "?機", "錘?", 3699.00,
"http://image.yx.com/12479122.jpg"));
list.add(new Product(3L, "華為META20", "?機", "華為", 4499.00,
"http://image.yx.com/12479122.jpg"));
list.add(new Product(4L, "??Pro", "?機", "??", 4299.00,
"http://image.yx.com/12479122.jpg"));
list.add(new Product(5L, "榮耀V20", "?機", "華為", 2799.00,
"http://image.yx.com/12479122.jpg"));
// 添加索引數(shù)據(jù)
productRepository.saveAll(list);
}2.2.2 查詢索引數(shù)據(jù)
1.根據(jù)id查詢數(shù)據(jù)
@Test
public void findById() {
Optional<Product> optional = productRepository.findById(1L);
Product defaultProduct = new Product();
defaultProduct.setTitle("默認商品數(shù)據(jù)");
// orElse(T other)?法:如果Optional對象中封裝的泛型為null,則將orElse()?法的參數(shù)作為返回值
Product product = optional.orElse(defaultProduct);
System.err.println(product);
}2.查詢所有數(shù)據(jù)
@Test
public void findAll() {
Iterable<Product> list = productRepository.findAll();
list.forEach(System.err::println);
}2.2.3 ?定義?法查詢

在ProductRepository接?中定義根據(jù)商品的價格區(qū)間查詢商品數(shù)據(jù)的findByPriceBetween()?法。
/** * 根據(jù)商品的價格區(qū)間查詢商品數(shù)據(jù) * @param from 開始價格 * @param to 結(jié)束價格 * @return 符合條件的商品數(shù)據(jù) */ List<Product> findByPriceBetween(Double from, Double to);
?需寫實現(xiàn),SDE會?動幫我們實現(xiàn)該?法,我們只需要?即可。在SpringDataESTests類中定義 findByPriceBetween()?法。
@Test
public void findByPriceBetween() {
List<Product> products = productRepository.findByPriceBetween(3000d, 5000d);
products.forEach(System.err::println);
}2.3 原?查詢案例
在com.csdn.mapper包下?定義搜索結(jié)果映射ProductSearchResultMapper類。
package com.csdn.esclient;
import com.google.gson.Gson;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 1.接口 SearchResultMapper 表示用來自定義查詢結(jié)果映射,將結(jié)果按照開發(fā)者的配置,進行重組,然后返回客戶端
* 2.重寫 mapResults
*/
/** ?定義查詢結(jié)果映射,?于處理?亮顯示 */
public class ProductSearchResulMapper implements SearchResultMapper {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
// 記錄總條數(shù)
long totalHits = searchResponse.getHits().getTotalHits();
// 記錄列表(泛型) - 構(gòu)建Aggregate使?
List<T> list = new ArrayList<>();
// 獲取搜索結(jié)果(真正的的記錄)
SearchHits hits = searchResponse.getHits();
Gson gson = new Gson();
for (SearchHit hit : hits) {
if (hits.getHits().length <= 0) {
return null;
}
// 將原本的JSON對象轉(zhuǎn)換成Map對象
Map<String, Object> map = hit.getSourceAsMap();
// 獲取?亮的字段Map
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
for (Map.Entry<String, HighlightField> highlightField : highlightFields.entrySet()) {
// 獲取?亮的Key
String key = highlightField.getKey();
// 獲取?亮的Value
HighlightField value = highlightField.getValue();
// 實際fragments[0]就是?亮的結(jié)果,?需遍歷拼接
Text[] fragments = value.getFragments();
// 因為?亮的字段必然存在于Map中,就是key值
map.put(key, fragments[0].toString());
}
// 把Map轉(zhuǎn)換成對象
T item = gson.fromJson(gson.toJson(map), aClass);
list.add(item);
}
// 返回的是帶分?的結(jié)果
return new AggregatedPageImpl<>(list, pageable, totalHits);
}
}Java測試類:
package com.csdn.es;
import com.qf.esclient.ProductSearchResulMapper;
import com.qf.pojo.Product;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringDataESTests {
@Autowired
private ElasticsearchTemplate template;
@Test
public void test01() {
// 1.創(chuàng)建原生查詢語句構(gòu)建
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
// 2.通過NativeSearchQueryBuilder指定過濾器條件
builder.withSourceFilter(new FetchSourceFilter(null,null));
// 3.添加詞條搜索條件
builder.withQuery(QueryBuilders.matchQuery("title","手機"));
// 4.分頁操作:當(dāng)前頁其實位置的下標(biāo)
builder.withPageable(PageRequest.of(0, 2, Sort.by(Sort.Direction.ASC,
"price")));
// 5.高亮顯示 TODO
HighlightBuilder.Field field = new HighlightBuilder.Field("title");
field.preTags("<span style='color:red'>");
field.postTags("</span>");
builder.withHighlightFields(field);
// 6.聚合:分組。參數(shù)解析:terms()方法指定分組的名稱(聚合名稱)
builder.addAggregation(AggregationBuilders.terms("brandAgg").field("brand"));
// 7.構(gòu)建查詢的條件,并且執(zhí)行查詢
AggregatedPage<Product> packages = template.queryForPage(builder.build(), Product.class,new ProductSearchResulMapper());
long total = packages.getTotalElements();
int totalPages = packages.getTotalPages();
List<Product> list = packages.getContent();
System.out.println("總條數(shù):" + total);
System.out.println("總?數(shù):" + totalPages);
System.out.println("數(shù)據(jù):");
list.forEach(System.out::println);
// 聚合
/**
Aggregations aggregations = packages.getAggregations();
// 導(dǎo)包org.elasticsearch.search.aggregations.bucket.terms.Terms
Terms terms = aggregations.get("brandAgg");
terms.getBuckets().forEach(b -> {
System.err.println("品牌:" + b.getKeyAsString());
System.err.println("count:" + b.getDocCount());
});
*/
}
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot配置多數(shù)據(jù)源后mybatis攔截器失效的解決
這篇文章主要介紹了springboot配置多數(shù)據(jù)源后mybatis攔截器失效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Spring ApplicationListener監(jiān)聽器用法詳解
這篇文章主要介紹了Spring ApplicationListener監(jiān)聽器用法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11
使用springboot activiti關(guān)閉驗證自動部署方式
這篇文章主要介紹了使用springboot activiti關(guān)閉驗證自動部署方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
玩轉(zhuǎn)spring boot 結(jié)合jQuery和AngularJs(3)
玩轉(zhuǎn)spring boot,這篇文章主要介紹了結(jié)合jQuery和AngularJs,玩轉(zhuǎn)spring boot,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01
Spring Boot項目中定制PropertyEditors方法
在本篇文章里小編給大家分享的是一篇關(guān)于Spring Boot定制PropertyEditors的知識點內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。2019-11-11
詳解JavaScript中的函數(shù)聲明和函數(shù)表達式
這篇文章主要介紹了詳解JavaScript中的函數(shù)聲明和函數(shù)表達式,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-08-08
Java并發(fā)編程 interrupt()方法示例詳解
interrrupt()方法可以用來打斷正在運行的線程,也可以打斷sleep()、wait()、join()情況下的線程,但是這些情況下被打斷線程的打斷標(biāo)記不同,這篇文章主要介紹了Java并發(fā)編程 interrupt()方法示例詳解,需要的朋友可以參考下2023-06-06

