SpringBoot--實(shí)戰(zhàn)開(kāi)發(fā)--整合ElasticSearch(十七)

一滋戳、ElasticSearch簡(jiǎn)介

??ElasticSearch是一個(gè)基于Lucene的搜索服務(wù)器铺呵。它提供了一個(gè)分布式多用戶能力的全文搜索引擎忆嗜,基于RESTful web接口焰雕。Elasticsearch是用Java語(yǔ)言開(kāi)發(fā)的记焊,并作為Apache許可條款下的開(kāi)放源碼發(fā)布,是一種流行的企業(yè)級(jí)搜索引擎瘦穆。ElasticSearch用于云計(jì)算中纪隙,能夠達(dá)到實(shí)時(shí)搜索,穩(wěn)定扛或,可靠绵咱,快速,安裝使用方便熙兔。官方客戶端在Java悲伶、.NET(C#)艾恼、PHP、Python麸锉、Apache Groovy钠绍、Ruby和許多其他語(yǔ)言中都是可用的。根據(jù)DB-Engines的排名顯示花沉,Elasticsearch是最受歡迎的企業(yè)搜索引擎柳爽,其次是Apache Solr,也是基于Lucene碱屁。

https://docs.spring.io/spring-data/elasticsearch/docs/3.2.0.RC3/reference/html/#preface.versions
Spring Data Elasticsearch與Elasticsearch兼容列表:

Spring Data Elasticsearch Elasticsearch
3.2.x 6.8.1
3.1.x 6.2.2
3.0.x 5.5.0
2.1.x 2.4.0
2.0.x 2.2.0
1.3.x 1.5.2

二磷脯、Maven依賴(lài)

elasticsearch6.4.3與spring-boot2.1.8+


版本
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

elasticsearch7.3.1與spring-boot2.2.0M5+

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.0.M6</version>
    <relativePath/>
</parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
    </repository>
</repositories>

三、配置

# Elasticsearch
spring.data.elasticsearch.repositories.enabled = true
# 集群名(默認(rèn)值: elasticsearch)
spring.data.elasticsearch.cluster-name=elasticsearch
#spring.data.elasticsearch.cluster-name=elasticsearch
# 9200端口是用來(lái)讓HTTP REST API來(lái)訪問(wèn)ElasticSearch娩脾,而9300端口是傳輸層監(jiān)聽(tīng)的默認(rèn)端口
spring.elasticsearch.jest.uris=http://192.168.77.132:9200/
# 集群節(jié)點(diǎn)地址列表争拐,用逗號(hào)分隔。如果沒(méi)有指定晦雨,就啟動(dòng)一個(gè)客戶端節(jié)點(diǎn)
spring.data.elasticsearch.cluster-nodes = 192.168.77.132:9300
spring.data.elasticsearch.properties.path.logs=./elasticsearch/log
spring.data.elasticsearch.properties.path.data=./elasticsearch/data
# 存儲(chǔ)索引的位置
spring.data.elasticsearch.properties.path.home=/data/project/target/elastic
# 連接超時(shí)的時(shí)間
spring.data.elasticsearch.properties.transport.tcp.connect_timeout=120s
# 用戶名與密碼
#spring.data.elasticsearch.properties.shield.user= es:123456

四架曹、注解

1.類(lèi)上注解:
@Document (相當(dāng)于Hibernate實(shí)體的@Entity/@Table)(必寫(xiě)),加上了@Document注解之后闹瞧,默認(rèn)情況下這個(gè)實(shí)體中所有的屬性都會(huì)被建立索引绑雄、并且分詞。

類(lèi)型 屬性名 默認(rèn)值 說(shuō)明
String indexName 無(wú) 索引庫(kù)的名稱(chēng)奥邮,建議以項(xiàng)目的名稱(chēng)命名
String type “” 類(lèi)型万牺,建議以實(shí)體的名稱(chēng)命名
short shards 5 默認(rèn)分區(qū)數(shù)
short replica 1 每個(gè)分區(qū)默認(rèn)的備份數(shù)
String refreshInterval “1s” 刷新間隔
String indexStoreType “fs” 索引文件存儲(chǔ)類(lèi)型
  1. 主鍵注解:
    @Id (相當(dāng)于Hibernate實(shí)體的主鍵@Id注解)(必寫(xiě))
    只是一個(gè)標(biāo)識(shí),并沒(méi)有屬性洽腺。
  2. 屬性注解
    @Field (相當(dāng)于Hibernate實(shí)體的@Column注解)
    @Field默認(rèn)是可以不加的脚粟,默認(rèn)所有屬性都會(huì)添加到ES中。加上@Field之后蘸朋,@document默認(rèn)把所有字段加上索引失效核无,只有加@Field 才會(huì)被索引(同時(shí)也看設(shè)置索引的屬性是否為no)
類(lèi)型 屬性名 默認(rèn)值 說(shuō)明
FieldType type FieldType.Auto 自動(dòng)檢測(cè)屬性的類(lèi)型
FieldIndex index FieldIndex.analyzed 默認(rèn)情況下分詞
boolean store false 默認(rèn)情況下不存儲(chǔ)原文
String searchAnalyzer " " 指定字段搜索時(shí)使用的分詞器
String indexAnalyzer " " 指定字段建立索引時(shí)指定的分詞器
String[] ignoreFields {} 如果某個(gè)字段需要被忽略

type:字段類(lèi)型,是是枚舉:FieldType藕坯,可以是text团南、long、short炼彪、date吐根、integer、object等
text:存儲(chǔ)數(shù)據(jù)時(shí)候辐马,會(huì)自動(dòng)分詞拷橘,并生成索引
keyword:存儲(chǔ)數(shù)據(jù)時(shí)候,不會(huì)分詞建立索引
Numerical:數(shù)值類(lèi)型,分兩類(lèi)
基本數(shù)據(jù)類(lèi)型:long冗疮、interger萄唇、short、byte赌厅、double、float轿塔、half_float
浮點(diǎn)數(shù)的高精度類(lèi)型:scaled_float
需要指定一個(gè)精度因子特愿,比如10或100。elasticsearch會(huì)把真實(shí)值乘以這個(gè)因子后存儲(chǔ)勾缭,取出時(shí)再還原揍障。
Date:日期類(lèi)型
elasticsearch可以對(duì)日期格式化為字符串存儲(chǔ),但是建議我們存儲(chǔ)為毫秒值俩由,存儲(chǔ)為long毒嫡,節(jié)省空間。
index:是否索引幻梯,布爾類(lèi)型兜畸,默認(rèn)是true
store:是否存儲(chǔ),布爾類(lèi)型碘梢,默認(rèn)是false
analyzer:分詞器名稱(chēng)咬摇,這里的ik_max_word即使用ik分詞器

  1. 實(shí)體類(lèi)
@Document(indexName = "item",type = "docs", shards = 1, replicas = 0)
public class Goods {
    @Id
    private Long id;
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title; //標(biāo)題
    @Field(type = FieldType.Keyword)
    private String category;// 分類(lèi)
    @Field(type = FieldType.Keyword)
    private String brand; // 品牌
    @Field(type = FieldType.Double)
    private Double price; // 價(jià)格
    @Field(index = false, type = FieldType.Keyword)
    private String images; // 圖片地址
}

五、Elasticsearch操作

  1. 定義接口
@Component
public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {
}
  1. 索引操作
    使用:ElasticsearchTemplate 模板對(duì)象
    /**
     * Elasticsearch模板
     */
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    /**
     * 創(chuàng)建索引煞躬,會(huì)根據(jù)Goods類(lèi)的@Document注解信息來(lái)創(chuàng)建
     * 名稱(chēng)為:goods
     */
    @Test
    public void createIndex() {
        // 創(chuàng)建索引肛鹏,會(huì)根據(jù)Item類(lèi)的@Document注解信息來(lái)創(chuàng)建
        elasticsearchTemplate.createIndex(Goods.class);
        // 配置映射,會(huì)根據(jù)Item類(lèi)中的id恩沛、Field等字段來(lái)自動(dòng)完成映射
        elasticsearchTemplate.putMapping(Goods.class);
    }

    /**
     * 刪除索引
     * 可以根據(jù)類(lèi)名或索引名刪除在扰。
     */
    @Test
    public void deleteIndex() {
        elasticsearchTemplate.deleteIndex("goods");
    }
創(chuàng)建結(jié)果
  1. 文檔操作
    Spring Data 不需要寫(xiě)任何DAO處理,自動(dòng)根據(jù)方法名或類(lèi)的信息進(jìn)行CRUD操作雷客。只要你定義一個(gè)接口芒珠,然后繼承Repository提供的一些子接口,就能具備各種基本的CRUD功能搅裙。
    簡(jiǎn)介使用:
    /**
     * 新增文檔
     * 數(shù)據(jù)查詢(xún):goods為索引妓局,docs為文檔類(lèi)型,1為id,pretty為顯示樣式
     * http://192.168.77.132:9200/goods/docs/1?pretty
     */
    @Test
    public void addDocument() {
        Goods goods = new Goods(1L, "小米手機(jī)7", " 手機(jī)",
                "小米", 3499.00, "https://img13.360buyimg.com/n1/s450x450_jfs/t1/79993/29/9874/153231/5d7809f4E8f387bff/1dc9e1b6b262f0fb.jpg");
        Goods goods0 = goodsRepository.save(goods);
        log.info(JSON.toJSONString(goods0));
    }

    /**
     * 批量新增
     */
    @Test
    public void createDocumentList() {
        List<Goods> list = new ArrayList<>();
        list.add(new Goods(2L, "堅(jiān)果手機(jī)R1", " 手機(jī)", "錘子", 3699.00, "http://image.leyou.com/123.jpg"));
        list.add(new Goods(3L, "華為META10", " 手機(jī)", "華為", 4499.00, "http://image.leyou.com/3.jpg"));
        // 接收對(duì)象集合,實(shí)現(xiàn)批量新增
        goodsRepository.saveAll(list);
    }

    //    修改文檔
    //    修改和新增是同一個(gè)接口呈宇,區(qū)分的依據(jù)就是id好爬,這一點(diǎn)跟我們?cè)陧?yè)面發(fā)起PUT請(qǐng)求是類(lèi)似的。
    @Test
    public void findDocument() {
        // 查詢(xún)?nèi)可模惭b價(jià)格降序排序
        Iterable<Goods> goodsIterable = this.goodsRepository.findAll(Sort.by(Sort.Direction.DESC, "price"));
        goodsIterable.forEach(goods -> System.out.println(JSON.toJSONString(goods)));
    }
文檔操作

六存炮、Elasticsearch 高級(jí)查詢(xún)

發(fā)生 描述
must 該條款(查詢(xún))必須出現(xiàn)在匹配的文件,并將有助于得分。
filter 子句(查詢(xún))必須出現(xiàn)在匹配的文檔中穆桂。然而不像 must查詢(xún)的分?jǐn)?shù)將被忽略宫盔。Filter子句在過(guò)濾器上下文中執(zhí)行,這意味著評(píng)分被忽略享完,子句被考慮用于高速緩存灼芭。
should 子句(查詢(xún))應(yīng)該出現(xiàn)在匹配的文檔中。如果 bool查詢(xún)位于查詢(xún)上下文中并且具有mustor filter子句般又,則bool即使沒(méi)有should查詢(xún)匹配彼绷,文檔也將匹配該查詢(xún) 。在這種情況下茴迁,這些條款僅用于影響分?jǐn)?shù)寄悯。如果bool查詢(xún)是過(guò)濾器上下文 或者兩者都不存在,must或者filter至少有一個(gè)should查詢(xún)必須與文檔相匹配才能與bool查詢(xún)匹配堕义。這種行為可以通過(guò)設(shè)置minimum_should_match參數(shù)來(lái)顯式控制 猜旬。
must_not 子句(查詢(xún))不能出現(xiàn)在匹配的文檔中。子句在過(guò)濾器上下文中執(zhí)行倦卖,意味著評(píng)分被忽略洒擦,子句被考慮用于高速緩存。因?yàn)橛?jì)分被忽略怕膛,0所有文件的分?jǐn)?shù)被返回秘遏。
  1. 自定義方法
    Spring Data 的另一個(gè)強(qiáng)大功能,是根據(jù)方法名稱(chēng)自動(dòng)實(shí)現(xiàn)功能嘉竟。

比如:你的方法名叫做:findByTitle邦危,那么它就知道你是根據(jù)title查詢(xún),然后自動(dòng)幫你完成舍扰,無(wú)需寫(xiě)實(shí)現(xiàn)類(lèi)倦蚪。

當(dāng)然,方法名稱(chēng)要符合一定的約定:

關(guān)鍵字 方法名(示例) ES查詢(xún)
And findByNameAndPrice {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
Or findByNameOrPrice {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
Is findByName {"bool" : {"must" : {"field" : {"name" : "?"}}}}
Not findByNameNot {"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
Between findByPriceBetween {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
LessThanEqual findByPriceLessThan {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
GreaterThanEqual findByPriceGreaterThan {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
Before findByPriceBefore {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
After findByPriceAfter {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
Like findByNameLike {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
StartingWith findByNameStartingWith {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
EndingWith findByNameEndingWith {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
Contains/Containing findByNameContaining {"bool" : {"must" : {"field" : {"name" : {"query" : "?","analyze_wildcard" : true}}}}}
In findByNameIn(Collection<String>names) {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
NotIn findByNameNotIn(Collection<String>names) {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
Near findByStoreNear Not Supported Yet !
True findByAvailableTrue {"bool" : {"must" : {"field" : {"available" : true}}}}
False findByAvailableFalse {"bool" : {"must" : {"field" : {"available" : false}}}}
OrderBy findByAvailableTrueOrderByNameDesc {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}
  1. 價(jià)格區(qū)間查詢(xún)
/**
     * 根據(jù)價(jià)格區(qū)間查詢(xún)
     * @param price1
     * @param price2
     * @return
     */
List<Goods> findByPriceBetween(double price1, double price2);

@Test
public void indexList() {
    List<Goods> list = new ArrayList<>();
    list.add(new Goods(1L, "小米手機(jī)7", "手機(jī)", "小米", 3299.00, "http://image.leyou.com/13123.jpg"));
    list.add(new Goods(2L, "堅(jiān)果手機(jī)R1", "手機(jī)", "錘子", 3699.00, "http://image.leyou.com/13123.jpg"));
    list.add(new Goods(3L, "華為META10", "手機(jī)", "華為", 4499.00, "http://image.leyou.com/13123.jpg"));
    list.add(new Goods(4L, "小米Mix2S", "手機(jī)", "小米", 4299.00, "http://image.leyou.com/13123.jpg"));
    list.add(new Goods(5L, "榮耀V10", "手機(jī)", "華為", 2799.00, "http://image.leyou.com/13123.jpg"));
    // 接收對(duì)象集合边苹,實(shí)現(xiàn)批量新增
   goodsRepository.saveAll(list);
}

@Test
public void queryByPriceBetween(){
    List<Goods> list = this.goodsRepository.findByPriceBetween(2000.00, 3500.00);
    for (Goods goods: list) {
        System.out.println("goods= " + goods);
    }
}
  1. 基本查詢(xún)
@Test
public void testQuery(){
    // 詞條查詢(xún)
    MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米");
    // 執(zhí)行查詢(xún)
    Iterable<Item> items = this.itemRepository.search(queryBuilder);
    items.forEach(System.out::println);
}

Repository的search方法需要QueryBuilder參數(shù)陵且,elasticSearch為我們提供了一個(gè)對(duì)象QueryBuilders:
QueryBuilders提供了大量的靜態(tài)方法,用于生成各種不同類(lèi)型的查詢(xún)對(duì)象个束,例如:詞條慕购、模糊、通配符等QueryBuilder對(duì)象茬底。
elasticsearch提供很多可用的查詢(xún)方式沪悲,但是不夠靈活。如果想玩過(guò)濾或者聚合查詢(xún)等就很難了阱表。

  1. 自定義查詢(xún)
@Test
public void testNativeQuery(){
    // 構(gòu)建查詢(xún)條件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本的分詞查詢(xún)
    queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米"));
    // 執(zhí)行搜索殿如,獲取結(jié)果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 打印總條數(shù)
    System.out.println(items.getTotalElements());
    // 打印總頁(yè)數(shù)
    System.out.println(items.getTotalPages());
    items.forEach(System.out::println);
}

NativeSearchQueryBuilder:Spring提供的一個(gè)查詢(xún)條件構(gòu)建器贡珊,幫助構(gòu)建json格式的請(qǐng)求體
Page<item>:默認(rèn)是分頁(yè)查詢(xún),因此返回的是一個(gè)分頁(yè)的結(jié)果對(duì)象涉馁,包含屬性:
totalElements:總條數(shù)
totalPages:總頁(yè)數(shù)
Iterator:迭代器门岔,本身實(shí)現(xiàn)了Iterator接口,因此可直接迭代得到當(dāng)前頁(yè)的數(shù)據(jù)

  1. 分頁(yè)查詢(xún)
    利用NativeSearchQueryBuilder可以方便的實(shí)現(xiàn)分頁(yè):
@Test
public void testNativeQuery(){
    // 構(gòu)建查詢(xún)條件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本的分詞查詢(xún)
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機(jī)"));

    // 初始化分頁(yè)參數(shù)
    int page = 0;
    int size = 3;
    // 設(shè)置分頁(yè)參數(shù)
    queryBuilder.withPageable(PageRequest.of(page, size));

    // 執(zhí)行搜索烤送,獲取結(jié)果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 打印總條數(shù)
    System.out.println(items.getTotalElements());
    // 打印總頁(yè)數(shù)
    System.out.println(items.getTotalPages());
    // 每頁(yè)大小
    System.out.println(items.getSize());
    // 當(dāng)前頁(yè)
    System.out.println(items.getNumber());
    items.forEach(System.out::println);
}

可以發(fā)現(xiàn)寒随,Elasticsearch中的分頁(yè)是從第0頁(yè)開(kāi)始

  1. 排序
    排序也通用通過(guò)NativeSearchQueryBuilder完成:
@Test
public void testSort(){
    // 構(gòu)建查詢(xún)條件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本的分詞查詢(xún)
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手機(jī)"));

    // 排序
    queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));

    // 執(zhí)行搜索帮坚,獲取結(jié)果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 打印總條數(shù)
    System.out.println(items.getTotalElements());
    items.forEach(System.out::println);
}

  1. 聚合為桶
    桶就是分組妻往,比如這里我們按照品牌brand進(jìn)行分組:
@Test
public void testAgg(){
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 不查詢(xún)?nèi)魏谓Y(jié)果
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
    // 1、添加一個(gè)新的聚合叶沛,聚合類(lèi)型為terms蒲讯,聚合名稱(chēng)為brands忘朝,聚合字段為brand
    queryBuilder.addAggregation(
        AggregationBuilders.terms("brands").field("brand"));
    // 2灰署、查詢(xún),需要把結(jié)果強(qiáng)轉(zhuǎn)為AggregatedPage類(lèi)型
    AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
    // 3、解析
    // 3.1局嘁、從結(jié)果中取出名為brands的那個(gè)聚合溉箕,
    // 因?yàn)槭抢肧tring類(lèi)型字段來(lái)進(jìn)行的term聚合,所以結(jié)果要強(qiáng)轉(zhuǎn)為StringTerm類(lèi)型
    StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
    // 3.2悦昵、獲取桶
    List<StringTerms.Bucket> buckets = agg.getBuckets();
    // 3.3肴茄、遍歷
    for (StringTerms.Bucket bucket : buckets) {
        // 3.4、獲取桶中的key但指,即品牌名稱(chēng)
        System.out.println(bucket.getKeyAsString());
        // 3.5寡痰、獲取桶中的文檔數(shù)量
        System.out.println(bucket.getDocCount());
    }
}

  1. 嵌套聚合,求平均值
@Test
public void testSubAgg(){
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 不查詢(xún)?nèi)魏谓Y(jié)果
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));
    // 1棋凳、添加一個(gè)新的聚合拦坠,聚合類(lèi)型為terms,聚合名稱(chēng)為brands剩岳,聚合字段為brand
    queryBuilder.addAggregation(
        AggregationBuilders.terms("brands").field("brand")
        .subAggregation(AggregationBuilders.avg("priceAvg").field("price")) // 在品牌聚合桶內(nèi)進(jìn)行嵌套聚合贞滨,求平均值
    );
    // 2、查詢(xún),需要把結(jié)果強(qiáng)轉(zhuǎn)為AggregatedPage類(lèi)型
    AggregatedPage<Item> aggPage = (AggregatedPage<Item>) this.itemRepository.search(queryBuilder.build());
    // 3拍棕、解析
    // 3.1晓铆、從結(jié)果中取出名為brands的那個(gè)聚合,
    // 因?yàn)槭抢肧tring類(lèi)型字段來(lái)進(jìn)行的term聚合绰播,所以結(jié)果要強(qiáng)轉(zhuǎn)為StringTerm類(lèi)型
    StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
    // 3.2骄噪、獲取桶
    List<StringTerms.Bucket> buckets = agg.getBuckets();
    // 3.3、遍歷
    for (StringTerms.Bucket bucket : buckets) {
        // 3.4蠢箩、獲取桶中的key腰池,即品牌名稱(chēng)  3.5尾组、獲取桶中的文檔數(shù)量
        System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "臺(tái)");

        // 3.6.獲取子聚合結(jié)果:
        InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
        System.out.println("平均售價(jià):" + avg.getValue());
    }
}

七示弓、常見(jiàn)錯(cuò)誤:

  1. failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{fp9W6s1YS9aWKDtk9RmljQ}{192.168.169.128}{192.168.169.128:9300}]
    原因:版本不兼容

  2. java.lang.IllegalStateException: Received message from unsupported version: [6.4.3] minimal compatible version is: [6.8.0]
    版本問(wèn)題:
    請(qǐng)使用高版本讳侨。
    如果ES是7.3.1,SpringBoot請(qǐng)使用:2.2.0.M5+

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.M6</version>
        <relativePath/>
    </parent>
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
       <version>2.2.0.M6</version>
    </dependency>
  1. MapperParsingException[analyzer [ik_max_word] not found for field [title]]
    原因:版本問(wèn)題奏属。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跨跨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子囱皿,更是在濱河造成了極大的恐慌勇婴,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘱腥,死亡現(xiàn)場(chǎng)離奇詭異耕渴,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)齿兔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)橱脸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人分苇,你說(shuō)我怎么就攤上這事添诉。” “怎么了医寿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵栏赴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我靖秩,道長(zhǎng)须眷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任沟突,我火速辦了婚禮花颗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘事扭。我一直安慰自己捎稚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布求橄。 她就那樣靜靜地躺著今野,像睡著了一般。 火紅的嫁衣襯著肌膚如雪罐农。 梳的紋絲不亂的頭發(fā)上条霜,一...
    開(kāi)封第一講書(shū)人閱讀 49,784評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音涵亏,去河邊找鬼宰睡。 笑死蒲凶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拆内。 我是一名探鬼主播旋圆,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼麸恍!你這毒婦竟也來(lái)了灵巧?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤抹沪,失蹤者是張志新(化名)和其女友劉穎刻肄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體融欧,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敏弃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了噪馏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麦到。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖逝薪,靈堂內(nèi)的尸體忽然破棺而出隅要,到底是詐尸還是另有隱情蝴罪,我是刑警寧澤董济,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站要门,受9級(jí)特大地震影響虏肾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欢搜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一封豪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炒瘟,春花似錦吹埠、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至廓推,卻和暖如春刷袍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背樊展。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工呻纹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留堆生,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓雷酪,卻偏偏與公主長(zhǎng)得像淑仆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哥力,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容