1. 程式人生 > >小白都能看懂如何快速學習Elasticsearch。索引操作、新增資料、查詢資料、聚合

小白都能看懂如何快速學習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());
}

}

結果: 在這裡插入圖片描述