Spring Data Elasticsearch-代碼版
項目結構
配置文件
-
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.leyou.demo</groupId> <artifactId>es-demo</artifactId> <version>1.0-SNAPSHOT</version> <name>elasticsearch</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </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> <!-- 引入elasticSearch啓動器 --> <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> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <!-- maven插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
application.yml
spring: data: elasticsearch: cluster-name: elasticsearch # 集羣名稱 cluster-nodes: 192.168.79.128:9300 # 集羣地址
啓動類
-
EsApplication
package com.leyou; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @program: es-demo * @description: * @author: Mr.Xiao * @create: 2020-06-10 09:59 **/ @SpringBootApplication public class EsApplication { public static void main(String[] args) { SpringApplication.run(EsApplication.class); } }
實體類
-
Item
package com.leyou.es.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; /** * @program: es-demo * @description: * @author: Mr.Xiao * @create: 2020-06-10 10:00 **/ @AllArgsConstructor @NoArgsConstructor @Data /* indexName: 索引庫名稱 type: 類型 shards: 分頁數量 replicas: 副本數量 */ @Document(indexName = "xiaoge2", type = "item", shards = 1, replicas = 1) public class Item { @Field(type = FieldType.Long) // 聲明字段的類型 @Id // 這個字段作爲索引庫的id來用 Long id; /* 指定爲text因爲標題將來要用來分詞 analyzer: 指定分詞器 */ @Field(type = FieldType.Text, analyzer = "ik_smart") String title; //標題 /* 因爲商品分類是不需要分詞的, 所以用keyword index: 將來會用來當做搜索, 過濾, 默認爲true這裏可以不寫 */ @Field(type = FieldType.Keyword, index = true) String category;// 分類 @Field(type = FieldType.Keyword, index = true) String brand; // 品牌 @Field(type = FieldType.Double, index = true) Double price; // 價格 /* 因爲商品分類是不需要分詞的, 所以用keyword index: false 將來不能被搜索或者過濾 */ @Field(type = FieldType.Keyword, index = false) String images; // 圖片地址 }
接口
-
ItemRepository
package com.leyou.es.repository; import com.leyou.es.pojo.Item; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import java.util.List; /** * @program: es-demo * @description: ElasticsearchRepository 第一個參數實體類類型, 第二個參數id類型 * @author: Mr.Xiao * @create: 2020-06-10 15:35 **/ // ElasticsearchRepository 跟 通用mapper一樣, 裏面包含了各種增刪改查 public interface ItemRepository extends ElasticsearchRepository<Item, Long> { /* 自己寫一個範圍查詢的方法, 它會自動幫你實現, 比通用mapper更牛逼 注意: 當你寫方法名時: 它會有提示, 要有根據他提供的單詞意思來給方法取名, 不是瞎寫的 */ List<Item> findByPriceBetween(Double begin, Double end); }
測試
-
EsTest
package com.leyou.es.demo; import com.leyou.es.pojo.Item; import com.leyou.es.repository.ItemRepository; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; 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.Page; import org.springframework.data.domain.PageRequest; 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.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; /** * @program: es-demo * @description: * @author: Mr.Xiao * @create: 2020-06-10 15:08 **/ @RunWith(SpringRunner.class) @SpringBootTest public class EsTest { @Autowired ElasticsearchTemplate template; // 註冊ElasticsearchTemplate對象 @Autowired private ItemRepository repository; // 註冊ItemRepository @Test public void testCreate() { // 創建索引庫 template.createIndex(Item.class); // 創建映射關係 template.putMapping(Item.class); /* 刪除索引 template.deleteIndex(Item.class); */ } /** * find開頭的方法是查詢 * save開頭的是新增, 如果id相同就是修改 * delete開頭的是刪除 */ @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")); // 接收對象集合,實現批量新增 repository.saveAll(list); } @Test public void testFind() { // 查詢所有 Iterable<Item> items = repository.findAll(); for (Item item : items) { System.out.println(item); } } @Test public void testFindPriceFilterBetween() { // 查詢價錢在2000-4000的商品 Iterable<Item> items = repository.findByPriceBetween(2000d, 4000d); for (Item item : items) { System.out.println(item); } } /** * 基本查詢: 分詞查詢 */ @Test public void testQuery(){ // QueryBuilders原生包下的, 構建條件 MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米"); // 執行查詢, 分詞查詢title中代用小米連個字的, 對象 Iterable<Item> items = repository.search(queryBuilder); items.forEach(System.out::println); } /** * 自定義查詢 */ @Test public void testNativeQuery(){ // 創建查詢構建器 spring提供的 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 結果過濾 FetchSourceFilter的兩個參數 includes excludes 效果就是elasticSearch中結果過濾的includes excludes queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"id", "title", "price"}, null)); // 添加基本的分詞查詢 queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米")); // 執行搜索,獲取結果 Page<Item> items = repository.search(queryBuilder.build()); // 打印總條數 System.out.println(items.getTotalElements()); // 打印總頁數 System.out.println(items.getTotalPages()); items.forEach(System.out::println); } /** * 分頁查詢 */ @Test public void testNativeQueryPage(){ // 創建查詢構建器 spring提供的 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本的分詞查詢 queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機")); // 初始化分頁參數 注意: 這裏的頁碼是從0開始, 不像我們之前是從1開始 int page = 0; int size = 3; // 設置分頁參數 queryBuilder.withPageable(PageRequest.of(page, size)); // 執行搜索,獲取結果 Page<Item> items = repository.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 testSort(){ // 創建查詢構建器 spring提供的 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加 不分詞查詢(category等於手機) queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機")); // 排序 根據price字段, 降序排序 queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC)); // 執行搜索,獲取結果 Page<Item> items = repository.search(queryBuilder.build()); // 打印總條數 System.out.println(items.getTotalElements()); items.forEach(System.out::println); } /** * 整合上面所有功能 */ @Test public void integration() { // 創建查詢構建器 spring提供的 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 結果過濾 queryBuilder.withSourceFilter(new FetchSourceFilter(new String[] {"id", "title", "price"}, null)); // 添加查詢條件 queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米")); // 排序 queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC)); // 分頁 queryBuilder.withPageable(PageRequest.of(0, 2)); // 執行查詢 Page<Item> list = repository.search(queryBuilder.build()); // 獲取總元素個數 System.out.println(list.getTotalElements()); // 獲取總頁數 System.out.println(list.getTotalPages()); // 獲取當前頁 System.out.println(list.getNumber()); // 獲取每頁大小 System.out.println(list.getSize()); // 獲取當前頁內容 System.out.println(list.getContent()); // 獲取當前頁內容 list.forEach(System.out::println); } /** * 聚合查詢 */ @Test public void testAgg() { // 創建查詢構建器 spring提供的 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 聚合名稱 String aggName = "popularBrand"; // 聚合 queryBuilder.addAggregation(AggregationBuilders.terms(aggName).field("brand")); // 查詢並返回帶聚合的結果 AggregatedPage<Item> items = template.queryForPage(queryBuilder.build(), Item.class); // 解析聚合 Aggregations aggregations = items.getAggregations(); // 獲取指定名稱的聚合(這裏用的實現類, 因爲用terms做的聚合, 被聚合的brand是String 所以這裏用的StringTerms) StringTerms terms = aggregations.get(aggName); // 獲取桶 List<StringTerms.Bucket> buckets = terms.getBuckets(); for (StringTerms.Bucket bucket : buckets) { System.out.println("key = " + bucket.getKey()); System.out.println("docCount = " + bucket.getDocCount()); } } }