小白都能看懂如何快速學習Elasticsearch。索引操作、新增資料、查詢資料、聚合
先匯入Elasticsearch座標
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
1.索引操作
首先我們準備好實體類:
public class Item { private Long id; private String title; //標題 private String category;// 分類 private String brand; // 品牌 private Double price; // 價格 private String images; // 圖片地址 }
我們要將實體類對映 例項:
@Document(indexName = "item",type = "docs", shards = 1, replicas = 0) public class Item { @Id private Long id; @Field(type = FieldType.Text, analyzer = "ik_max_word") private String title; //標題 @Field(type = FieldType.Keyword) private String category;// 分類 @Field(type = FieldType.Keyword) private String brand; // 品牌 @Field(type = FieldType.Double) private Double price; // 價格 @Field(index = false, type = FieldType.Keyword) private String images; // 圖片地址 }
建立索引 ElasticsearchTemplate中提供了建立索引的API: • 可以根據類的資訊自動生成,也可以手動指定indexName和Settings
對映相關的API: • 一樣,可以根據類的位元組碼資訊(註解配置)來生成對映,或者手動編寫對映
我們這裡採用類的位元組碼資訊建立索引並對映:
@Test public void createIndex() { // 建立索引,會根據Item類的@Document註解資訊來建立 esTemplate.createIndex(Item.class); // 配置對映,會根據Item類中的id、Field等欄位來自動完成對映 esTemplate.putMapping(Item.class); }
2.刪除索引
可以根據類名或索引名刪除。 示例:
@Test
public void deleteIndex() {
esTemplate.deleteIndex(Item.class);
// 根據索引名字刪除
//esTemplate.deleteIndex("item1");
}
3.新增文件資料
我們需要定義介面(相當於dao),然後繼承它就OK了。
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
}
3.1新增一個物件
@Autowired
private ItemRepository itemRepository;
@Test
public void index() {
Item item = new Item(1L, "小米手機7", " 手機",
"小米", 3499.00, "http://image.baidu.com/13123.jpg");
itemRepository.save(item);
}
去頁面查詢看看:
3.2批量新增
@Test
public void indexList() {
List<Item> list = new ArrayList<>();
list.add(new Item(2L, "堅果手機R1", " 手機", "錘子", 3699.00, "http://image.baidu.com/13123.jpg"));
list.add(new Item(3L, "華為META10", " 手機", "華為", 4499.00, "http://image.baidu.com/13123.jpg"));
// 接收物件集合,實現批量新增
itemRepository.saveAll(list);
}
再次去頁面查詢:
4.修改
修改和新增是同一個介面,區分的依據就是id。
@Test
public void index(){
Item item = new Item(1L, "蘋果XSMax", " 手機",
"小米", 3499.00, "http://image.baidu.com/13123.jpg");
itemRepository.save(item);
}
檢視結果:
5.查詢
5.1基本查詢
我們來試試查詢所有:
@Test
public void query(){
// 查詢全部,並安裝價格降序排序
Iterable<Item> items = this.itemRepository.findAll(Sort.by("price").descending());
for (Item item : items) {
System.out.println("item = " + item);
}
}
5.2自定義方法查詢
先來看最基本的match query:
@Test
public void search(){
// 構建查詢條件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 新增基本分詞查詢
queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米手機"));
// 搜尋,獲取結果
Page<Item> items = this.itemRepository.search(queryBuilder.build());
// 總條數
long total = items.getTotalElements();
System.out.println("total = " + total);
for (Item item : items) {
System.out.println(item);
}
}
5.3分頁查詢
利用NativeSearchQueryBuilder可以方便的實現分頁:
@Test
public void searchByPage(){
// 構建查詢條件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 新增基本分詞查詢
queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機"));
// 分頁:
int page = 0;
int size = 2;
queryBuilder.withPageable(PageRequest.of(page,size));
// 搜尋,獲取結果
Page<Item> items = this.itemRepository.search(queryBuilder.build());
// 總條數
long total = items.getTotalElements();
System.out.println("總條數 = " + total);
// 總頁數
System.out.println("總頁數 = " + items.getTotalPages());
// 當前頁
System.out.println("當前頁:" + items.getNumber());
// 每頁大小
System.out.println("每頁大小:" + items.getSize());
for (Item item : items) {
System.out.println(item);
}
}
結果:
可以發現,Elasticsearch中的分頁是從第0頁開始。
5.4排序
排序也通用通過NativeSearchQueryBuilder完成:
@Test
public void searchAndSort(){
// 構建查詢條件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 新增基本分詞查詢
queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機"));
// 排序
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
// 搜尋,獲取結果
Page<Item> items = this.itemRepository.search(queryBuilder.build());
// 總條數
long total = items.getTotalElements();
System.out.println("總條數 = " + total);
for (Item item : items) {
System.out.println(item);
}
}
5.5 聚合
Elasticsearch中的聚合,包含多種型別,最常用的兩種,一個叫桶,一個叫度量. 桶:就是對資料進行分組。 度量:分組完成以後,我們一般會對組中的資料進行聚合運算,例如求平均值、最大、最小、求和等,這些在ES中稱為度量
比較常用的一些度量聚合方式: • Avg Aggregation:求平均值 • Max Aggregation:求最大值 • Min Aggregation:求最小值 • Percentiles Aggregation:求百分比 • Stats Aggregation:同時返回avg、max、min、sum、count等 • Sum Aggregation:求和 • Top hits Aggregation:求前幾 • Value Count Aggregation:求總數 • …… 注意:在ES中,需要進行聚合、排序、過濾的欄位其處理方式比較特殊,因此不能被分詞。這裡我們將color和make這兩個文字型別的欄位設定為keyword型別,這個型別不會被分詞,將來就可以參與聚合
5.6 巢狀聚合,求平均值
程式碼:
@Test
public void testSubAgg(){
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 不查詢任何結果
queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
// 1、新增一個新的聚合,聚合型別為terms,聚合名稱為brands,聚合欄位為brand
queryBuilder.addAggregation(
AggregationBuilders.terms("brands").field("brand")
.subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶內進行巢狀聚合,求平均值
);
// 2、查詢,需要把結果強轉為AggregatedPage型別
AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
// 3、解析
// 3.1、從結果中取出名為brands的那個聚合,
// 因為是利用String型別欄位來進行的term聚合,所以結果要強轉為StringTerm型別
StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
// 3.2、獲取桶
List<StringTerms.Bucket> buckets = agg.getBuckets();
// 3.3、遍歷
for (StringTerms.Bucket bucket : buckets) {
// 3.4、獲取桶中的key,即品牌名稱 3.5、獲取桶中的文件數量
System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "臺");
// 3.6.獲取子聚合結果:
InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
System.out.println("平均售價:" + avg.getValue());
}
}
結果: