一滋戳、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)型 |
- 主鍵注解:
@Id (相當(dāng)于Hibernate實(shí)體的主鍵@Id注解)(必寫(xiě))
只是一個(gè)標(biāo)識(shí),并沒(méi)有屬性洽腺。 - 屬性注解
@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分詞器
- 實(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操作
- 定義接口
@Component
public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {
}
- 索引操作
使用: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");
}
- 文檔操作
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ù)被返回秘遏。 |
- 自定義方法
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}}}} |
- 價(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);
}
}
- 基本查詢(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)等就很難了阱表。
- 自定義查詢(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ù)
- 分頁(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)始。
- 排序
排序也通用通過(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);
}
- 聚合為桶
桶就是分組妻往,比如這里我們按照品牌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());
}
}
- 嵌套聚合,求平均值
@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ò)誤:
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}]
原因:版本不兼容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>
- MapperParsingException[analyzer [ik_max_word] not found for field [title]]
原因:版本問(wèn)題奏属。