本文使用內容 springBoot2.2.5.RELEASE版本 Elasticsearch7.6.2 linux版本的 SpringDataElasticSearch與Springboot版本對應
一、操作准備
1、導入依賴
此處版本
2.2.5.RELEASE
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
2、創建application.yml文件
spring:
elasticsearch:
rest:
uris: http://192.168.0.211:9200
此處的ip:端口 是自己的Elasticsearch的,如果為集群可以以逗號(,)隔開
3、創建實體類對象

1 package cn.cqsw.elasticsearch.pojo; 2 3 import org.springframework.data.annotation.Id; 4 import org.springframework.data.elasticsearch.annotations.Document; 5 import org.springframework.data.elasticsearch.annotations.Field; 6 import org.springframework.data.elasticsearch.annotations.FieldType; 7 8 import java.io.Serializable; 9 10 @Document(indexName = "item" , type = "_doc",shards = 1,replicas = 0) 11 public class Item implements Serializable { 12 @Id //注意此處的@Id必須為springframework包下面的id import org.springframework.data.annotation.Id; 13 Long id; 14 @Field(type = FieldType.Text,analyzer = "ik_max_word") 15 String title; //標題 16 @Field(type = FieldType.Keyword) 17 String category;// 分類 18 @Field(type = FieldType.Keyword) 19 String brand; // 品牌 20 @Field(type = FieldType.Double) 21 Double price; // 價格 22 @Field(type = FieldType.Keyword,index = false) 23 String images; // 圖片地址 24 25 public Long getId() { 26 return id; 27 } 28 29 public void setId(Long id) { 30 this.id = id; 31 } 32 33 public String getTitle() { 34 return title; 35 } 36 37 public void setTitle(String title) { 38 this.title = title; 39 } 40 41 public String getCategory() { 42 return category; 43 } 44 45 public void setCategory(String category) { 46 this.category = category; 47 } 48 49 public String getBrand() { 50 return brand; 51 } 52 53 public void setBrand(String brand) { 54 this.brand = brand; 55 } 56 57 public Double getPrice() { 58 return price; 59 } 60 61 public void setPrice(Double price) { 62 this.price = price; 63 } 64 65 public String getImages() { 66 return images; 67 } 68 69 public void setImages(String images) { 70 this.images = images; 71 } 72 73 public Item() { 74 } 75 76 public Item(Long id, String title, String category, String brand, Double price, String images) { 77 this.id = id; 78 this.title = title; 79 this.category = category; 80 this.brand = brand; 81 this.price = price; 82 this.images = images; 83 } 84 85 86 @Override 87 public String toString() { 88 return "Item{" + 89 "id=" + id + 90 ", title='" + title + '\'' + 91 ", category='" + category + '\'' + 92 ", brand='" + brand + '\'' + 93 ", price=" + price + 94 ", images='" + images + '\'' + 95 '}'; 96 }
注解參數含義解釋
Spring Data通過注解來聲明字段的映射屬性,有下面的三個注解: - `@Document` 作用在類,標記實體類為文檔對象,一般有四個屬性 - indexName:對應索引庫名稱 - type:對應在索引庫中的類型 在ElasticSearch7.x中取消了type的概念 - shards:分片數量,默認5 - replicas:副本數量,默認1 - `@Id` 作用在成員變量,標記一個字段作為id主鍵 - `@Field` 作用在成員變量,標記為文檔的字段,並指定字段映射屬性: - type:字段類型,取值是枚舉:FieldType - index:是否索引,布爾類型,默認是true - store:是否存儲,布爾類型,默認是false - analyzer:分詞器名稱:ik_max_word ik分詞器內容,看另外一個隨筆:https://www.cnblogs.com/TJ21/p/12642242.html
4、創建一個空的Repository的接口
不明白為什么可以看一些Spring-Data文檔
5、創建啟動類
@SpringBootApplication public class ElasticSearchApplication { public static void main(String[] args) { SpringApplication.run(ElasticSearchApplication.class); } }
6、創建測試
測試
注意
此處使用
ElasticsearchRestTemplate 模板原因為 : ElasticsearchTemplate 模板使用的是使用的 TransportClient 此客戶端在ElasticSearch7的版本中不再推薦使用,
在8的版本中將被移除,官方建議使用:High Level REST Client (高級Test客戶端)
不使用ElasticsearchTemplate
原因查看官方文檔:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.6.RELEASE/reference/html/#elasticsearch.clients.transport
使用ElasticsearchRestTemplate 原因:官方文檔:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.6.RELEASE/reference/html/#elasticsearch.operations.resttemplate
這樣我們使用的就是: High Level REST Client (高級Test客戶端)
使用junit4
@RunWith(SpringRunner.class) @SpringBootTest(classes = ElasticSearchApplication.class) public class ElasticisesTest { @Autowired private ElasticsearchRestTemplate elasticsearchRestTemplate; @Autowired private ItemRepository itemRepository; @Test public void addIndexTest() { this.elasticsearchRestTemplate.createIndex(Item.class); this.elasticsearchRestTemplate.putMapping(Item.class); } @Test public void deleteIndex() { this.elasticsearchRestTemplate.deleteIndex("item"); } /** * 新增和批量新增 */ @Test public void create() { /*新增*/ // Item item = new Item(1L, "小米手機7", " 手機", "小米", 3499.00, "http://image.leyou.com/13123.jpg"); // this.itemRepository.save(item); List<Item> list = new ArrayList<>(); list.add(new Item(2L, "堅果手機R1", " 手機", "錘子", 3699.00, "http://image.leyou.com/123.jpg")); list.add(new Item(3L, "華為META10", " 手機", "華為", 4499.00, "http://image.leyou.com/3.jpg")); // 接收對象集合,實現批量新增 this.itemRepository.saveAll(list); } /** * 查詢全部 */ @Test public void find() { Optional<Item> item = this.itemRepository.findById(1L); System.out.println("item.get() = " + item.get()); } /** * 查詢並排序 */ @Test public void findAllSort() { Iterable<Item> items = this.itemRepository.findAll(Sort.by("price").descending()); items.forEach(System.out::println); } /** * 根據title查詢 */ @Test public void findByTitle() { Iterable<Item> items = this.itemRepository.findByTitle("手機"); items.forEach(System.out::println); } /** * 查詢價格區間 */ @Test public void findByPrice() { List<Item> byPriceBetween = this.itemRepository.findByPriceBetween(3699d, 4499d); byPriceBetween.forEach(System.out::println); } /** * 添加測試數據 */ @Test public void indexList() { List<Item> list = new ArrayList<>(); list.add(new Item(1L, "小米手機7", "手機", "小米", 3299.00, "http://image.leyou.com/13123.jpg")); list.add(new Item(2L, "堅果手機R1", "手機", "錘子", 3699.00, "http://image.leyou.com/13123.jpg")); list.add(new Item(3L, "華為META10", "手機", "華為", 4499.00, "http://image.leyou.com/13123.jpg")); list.add(new Item(4L, "小米Mix2S", "手機", "小米", 4299.00, "http://image.leyou.com/13123.jpg")); list.add(new Item(5L, "榮耀V10", "手機", "華為", 2799.00, "http://image.leyou.com/13123.jpg")); // 接收對象集合,實現批量新增 itemRepository.saveAll(list); } /** * 通過標題查詢 */ @Test public void testSearch() { // 通過查詢構建器構建查詢條件 MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "手機"); //執行查詢 Iterable<Item> items = this.itemRepository.search(matchQueryBuilder); items.forEach(System.out::println); } @Test public void testNative() { //構建自定義查詢構建器 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); //添加基本的查詢條件 MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "手機"); //執行查詢獲取分頁結果集 nativeSearchQueryBuilder.withQuery(matchQueryBuilder); Page<Item> items = this.itemRepository.search(nativeSearchQueryBuilder.build()); System.out.println("items.getTotalElements() = " + items.getTotalElements()); System.out.println("items.getTotalPages() = " + items.getTotalPages()); items.forEach(System.out::println); } /** * 分頁查詢 */ @Test public void testNativeQuery() { // 構建查詢條件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本的分詞查詢 queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機")); // 初始化分頁參數 int page = 0; int size = 3; // 設置分頁參數 queryBuilder.withPageable(PageRequest.of(page, size)); // 執行搜索,獲取結果 Page<Item> items = this.itemRepository.search(queryBuilder.build()); // 打印總條數 System.out.println(items.getTotalElements()); // 打印總頁數 System.out.println(items.getTotalPages()); // 每頁大小 System.out.println(items.getSize()); // 當前頁 System.out.println(items.getNumber()); items.forEach(System.out::println); } @Test public void testAggs() { //初始化自定義構建查詢器 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); //添加聚合 queryBuilder.addAggregation(AggregationBuilders.terms("brandAgg").field("brand")); //添加結果集過濾不包括任何字段 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{}, null)); //執行查詢 AggregatedPage<Item> itemPage = (AggregatedPage<Item>)this.itemRepository.search(queryBuilder.build()); /* 解析聚合結果集,根據聚合的類型以及字段類型,要進行強轉,不然無法獲取桶 brand-是字符串類型的,聚合類型是詞條類型的 brandAgg-通過聚合名稱獲取聚合對象 使用StringTerms強轉的時候出現錯誤 */ ParsedStringTerms brandAgg =(ParsedStringTerms) itemPage.getAggregation("brandAgg"); //獲取桶 List<? extends Terms.Bucket> buckets = brandAgg.getBuckets(); //遍歷輸出 buckets.forEach(bucket -> { System.out.println("bucket.getKeyAsString() = " + bucket.getKeyAsString()); //獲取條數 System.out.println("bucket.getDocCount() = " + bucket.getDocCount()); }); } /** * 子聚合 */ @Test public void testSubAggs() { //初始化自定義構建查詢器 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); //添加聚合 queryBuilder.addAggregation(AggregationBuilders.terms("brandAgg").field("brand").subAggregation(AggregationBuilders.avg("price_avg").field("price"))); //添加結果集過濾不包括任何字段 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{}, null)); //執行查詢 AggregatedPage<Item> itemPage = (AggregatedPage<Item>)this.itemRepository.search(queryBuilder.build()); /* 解析聚合結果集,根據聚合的類型以及字段類型,要進行強轉,不然無法獲取桶 brand-是字符串類型的,聚合類型是詞條類型的 brandAgg-通過聚合名稱獲取聚合對象 使用StringTerms強轉的時候出現錯誤 */ StringTerms brandAgg =(StringTerms) itemPage.getAggregation("brandAgg"); //獲取桶 List<StringTerms.Bucket> buckets = brandAgg.getBuckets(); //遍歷輸出 buckets.forEach(bucket -> { System.out.println("bucket.getKeyAsString() = " + bucket.getKeyAsString()); //獲取條數 System.out.println("bucket.getDocCount() = " + bucket.getDocCount()); //獲取子聚合的map集合:key-聚合名稱,value-對應的子聚合對象 Map<String, Aggregation> stringAggregationMap = bucket.getAggregations().asMap(); /* 以前使用的InternalAvg強轉出現轉換異常 */ ParsedAvg price_avg =(ParsedAvg) stringAggregationMap.get("price_avg"); System.out.println("price_avg.getValue() = " + price_avg.getValue()); }); } }