ElasticSearch高級客戶端RestHighLevelClient
記4個對象
1)導包
<!--引入es的坐標-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
2)配置
#配置文件:聲明ES的主機、端口
heima:
host: 192.168.200.128
port: 9200
/*配置類:連接ES,生成RestHighLevelClient*/
3)代碼
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticSearchConfig {
private String host;
private int port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
@Bean
public RestHighLevelClient client(){
return new RestHighLevelClient(RestClient.builder(
new HttpHost(
host,
port,
"http"
)
));
}
}
索引庫維護
索引庫維護:“索引庫、映射、文檔、域”增刪改
1)創建索引庫
public void addIndex() throws IOException {
//1.使用client獲取操作索引的對象
IndicesClient indicesClient = client.indices();
//2.具體操作,獲取返回值
CreateIndexRequest createRequest = new CreateIndexRequest("goods");
CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);
//3.根據返回值判斷結果
System.out.println(response.isAcknowledged());
}
2)創建映射
public void addIndexAndMapping() throws IOException {
//1.使用client獲取操作索引的對象
IndicesClient indicesClient = client.indices();
//2.具體操作,獲取返回值
CreateIndexRequest createRequest = new CreateIndexRequest("itcast");
//2.1 設置mappings
String mapping = "{\n" +
"\t\"properties\": {\n" +
"\t\t\"title\": {\n" +
"\t\t\t\"type\": \"text\",\n" +
"\t\t\t\"analyzer\": \"ik_smart\"\n" +
"\t\t},\n" +
"\t\t\"price\": { \n" +
"\t\t\t\"type\": \"double\"\n" +
"\t\t},\n" +
"\t\t\"createTime\": {\n" +
"\t\t\t\"type\": \"date\"\n" +
"\t\t},\n" +
"\t\t\"categoryName\": {\t\n" +
"\t\t\t\"type\": \"keyword\"\n" +
"\t\t},\n" +
"\t\t\"brandName\": {\t\n" +
"\t\t\t\"type\": \"keyword\"\n" +
"\t\t},\n" +
"\n" +
"\t\t\"spec\": {\t\t\n" +
"\t\t\t\"type\": \"object\"\n" +
"\t\t},\n" +
"\t\t\"saleNum\": {\t\n" +
"\t\t\t\"type\": \"integer\"\n" +
"\t\t},\n" +
"\t\t\n" +
"\t\t\"stock\": {\t\n" +
"\t\t\t\"type\": \"integer\"\n" +
"\t\t}\n" +
"\t}\n" +
"}";
createRequest.mapping(mapping,XContentType.JSON);
CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);
//3.根據返回值判斷結果
System.out.println(response.isAcknowledged());
}
PUT goods
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart"
},
"price": {
"type": "double"
},
"createTime": {
"type": "date"
},
"categoryName": {
"type": "keyword"
},
"brandName": {
"type": "keyword"
},
"spec": {
"type": "object"
},
"saleNum": {
"type": "integer"
},
"stock": {
"type": "integer"
}
}
}
}
3)添加文檔
public void importData() throws IOException {
//1.查詢所有數據,mysql
List<Goods> goodsList = goodsMapper.findAll();
//System.out.println(goodsList.size());
//2.bulk導入
BulkRequest bulkRequest = new BulkRequest();
//2.1 循環goodsList,創建IndexRequest添加數據
for (Goods goods : goodsList) {
//2.2 設置spec規格信息 Map的數據 specStr:{}
//goods.setSpec(JSON.parseObject(goods.getSpecStr(),Map.class));
String specStr = goods.getSpecStr();
//將json格式字符串轉為Map集合
Map map = JSON.parseObject(specStr, Map.class);
//設置spec map
goods.setSpec(map);
//將goods對象轉換為json字符串
String data = JSON.toJSONString(goods);//map --> {}
IndexRequest indexRequest = new IndexRequest("goods");
indexRequest.id(goods.getId()+"").source(data, XContentType.JSON);
bulkRequest.add(indexRequest);
}
BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(response.status());
}
高級操作
bulk批量操作
//作用:減少請求次數,提高效率
BulkRequest bulkRequest = new BulkRequest();
client.bulk(bulkRequest,RequestOptions.DEFAULT);
bulkRequest.add()
ES搜索
搜索套路代碼
public void search(Map searchMap) throws IOException {
//1. 構建查詢請求對象,指定查詢的索引名稱
SearchRequest searchRequest = new SearchRequest("goods");
//2. 創建查詢條件構建器SearchSourceBuilder
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//多條件拼接,布爾查詢構建器
//3. 封裝查詢條件、查詢方式
//3.1 基礎查詢(使用QueryBuilders構建的查詢對象),使用boolQueryBuilder封裝
if(StringUtils.isNotBlank(searchMap.get("keyword"))){
QueryBuilder keyword = QueryBuilders.matchQuery("title", searchMap.get("keyword"));
boolQueryBuilder.filter(keyword);
}
....
//3.2 高級查詢(分頁,排序、分組、高亮)
if(分頁判斷){
}
sourceBuilder.from(curPage);
sourceBuilder.size(size);
if(分組聚合判斷){//可以有多個;Aggregation:聚合
AggregationBuilder agg1 = AggregationBuilders.terms("goods_brands").field("brandName").size(100);
AggregationBuilder agg2 = AggregationBuilders.terms("goods_category").field("categoryName").size(100);
...
sourceBulider.aggregation(agg1);
sourceBulider.aggregation(agg2);
}
if(StringUtils.isNotBlank(searchMap.get("keyword"))){//高亮判斷
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
searchSourceBuilder.highlighter(highlightBuilder);
}
//4. 整合所有查詢條件
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(sourceBuilder);
//5. 使用RestHighLevelClient執行搜索searchRequest
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
//6. 獲取搜索結果
SearchHits searchHits = searchResponse.getHits();
//6.1 獲取總記錄數
long value = searchHits.getTotalHits().value;
System.out.println("總記錄數:"+value);
List<Goods> goodsList = new ArrayList<>();
//6.2 數據列表
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
//獲取json字符串格式的數據
String sourceAsString = hit.getSourceAsString();
//轉為java對象
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
//6.3 高亮結果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField HighlightField = highlightFields.get("title");
Text[] fragments = HighlightField.fragments();
//替換為“高亮內容”
if(fragments != null && fragments.size() > 0){
goods.setTitle(fragments[0].toString());
}
goodsList.add(goods);
}
//6.4 分組結果
// 獲取聚合結果
List brands = new ArrayList();
Aggregations aggregations = searchResponse.getAggregations();
Map<String, Aggregation> aggregationMap = aggregations.asMap();
Terms goods_brands = (Terms) aggregationMap.get("goods_brands");
List<? extends Terms.Bucket> buckets = goods_brands.getBuckets();
for (Terms.Bucket bucket : buckets) {
Object key = bucket.getKey();
brands.add(key);
}
}
ES支持的查詢方式
9用的多
QueryBuilders構建:
1)match_all 查詢所有
QueryBuilder query = QueryBuilders.matchAllQuery();//查詢所有文檔
2)term 詞條查詢:不分詞,精確匹配
QueryBuilder query = QueryBuilders.termQuery("title","華為");
3)match 分詞查詢:先分詞,后查詢(分詞后默認使用"or"連接條件)
QueryBuilder query = QueryBuilders.macthQuery("title", "華為手機");
4) wildcard 模糊查詢
WildcardQueryBuilder query = QueryBuilders.wildcardQuery("title", "華*");
5) regexp 正則查詢
RegexpQueryBuilder query = QueryBuilders.regexpQuery("title", "\\w+(.)*");
6) prefix 前綴查詢
PrefixQueryBuilder query = QueryBuilders.prefixQuery("brandName", "三");
7) range 范圍查詢
1)QueryBuilder query = QueryBuilders.rangeQuery("").gte("").lte("");
//范圍查詢
2)RangeQueryBuilder query = QueryBuilders.rangeQuery("price");
//指定下限
query.gte(2000);
//指定上限
query.lte(3000);
8) queryString 條件字符串查詢(作用:一值多域(輸入華為,在title和category等等有,都可查)查詢,支持分詞)
QueryStringQueryBuilder query = QueryBuilders.queryStringQuery("華為手機").field("title").field("categoryName").field("brandName").defaultOperator(Operator.AND);
queryStringQuery支持and和or的連接符;
simplequeryStringQuery不支持
9) bool 布爾查詢,多條件拼接的條件構建器.連接的方式有下面4種-----》對8)多條件查詢的拼接
must:(and)必須滿足,計算分值
must_not:(not)必須不滿足,計算分值
should:(or)可以滿足,計算分值
---------------------------------
filter:必須滿足,不計算分值(效率高)
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
實例:
/**
* 9,布爾查詢:boolQuery
* 1. 查詢品牌名稱為:華為
* 2. 查詢標題包含:手機
* 3. 查詢價格在:2000-3000
*/
@Test
public void testBoolQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("goods");
SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
//1.構建boolQuery
BoolQueryBuilder query = QueryBuilders.boolQuery();
//2.構建各個查詢條件
//2.1 查詢品牌名稱為:華為
QueryBuilder termQuery = QueryBuilders.termQuery("brandName","華為");
query.must(termQuery);
//2.2. 查詢標題包含:手機
QueryBuilder matchQuery = QueryBuilders.matchQuery("title","手機");
query.filter(matchQuery);
//2.3 查詢價格在:2000-3000;gte大於等於;lte小於等於
QueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
((RangeQueryBuilder) rangeQuery).gte(2000);
((RangeQueryBuilder) rangeQuery).lte(3000);
query.filter(rangeQuery);
//3.使用boolQuery連接
sourceBulider.query(query);
searchRequest.source(sourceBulider);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
//獲取記錄數
long value = searchHits.getTotalHits().value;
System.out.println("總記錄數:"+value);
List<Goods> goodsList = new ArrayList<>();
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
//轉為java
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
goodsList.add(goods);
}
for (Goods goods : goodsList) {
System.out.println(goods);
}
}
SearchSourceBuilder構建:
1)分頁
searchSourceBuilder.from(0)
searchSourceBuilder.size(10)
2)排序
searchSourceBuilder.sort(“field”,SortOrder.DESC|SortOrder.ASC);
3)高亮(指定高亮域、設置高亮前綴、后綴)
4)分組聚合
(指標聚合(max,min,avg,sum)和桶聚合(groupby),桶聚合不能對text類型的使用:例:搜索面板上的品牌)
AggregationBuilder agg = AggregationBuilders.terms("goods_brands").field("brandName").size(100);//goods_brands是自己起的名字,brandName桶聚合的字段
sourceBulider.aggregation(agg);
高亮的代碼操作
/**
*
* 11,高亮查詢:
* 1. 設置高亮
* * 高亮字段
* * 前綴
* * 后綴
* 2. 將高亮了的字段數據,替換原有數據
*/
@Test
public void testHighLightQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("goods");
SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
// 1. 查詢title包含手機的數據
MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手機");
sourceBulider.query(query);
//設置高亮
HighlightBuilder highlighter = new HighlightBuilder();
//設置三要素(前后綴有默認的<em></em>)
highlighter.field("title");
highlighter.preTags("<font color='red'>");
highlighter.postTags("</font>");
sourceBulider.highlighter(highlighter);
// 2. 查詢品牌列表
/*
參數:
1. 自定義的名稱,將來用於獲取數據
2. 分組的字段
*/
AggregationBuilder agg = AggregationBuilders.terms("goods_brands").field("brandName").size(100);
sourceBulider.aggregation(agg);
searchRequest.source(sourceBulider);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
//獲取記錄數
long value = searchHits.getTotalHits().value;
System.out.println("總記錄數:"+value);
List<Goods> goodsList = new ArrayList<>();
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
//轉為java
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
// 獲取高亮結果,替換goods中的title
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField HighlightField = highlightFields.get("title");
Text[] fragments = HighlightField.fragments();//高亮片段(現在只有一個:是數組的第一個元素);域可能是多值得,所以返回的數組
//替換
goods.setTitle(fragments[0].toString());
goodsList.add(goods);
}
for (Goods goods : goodsList) {
System.out.println(goods);
}
// 獲取聚合結果
Aggregations aggregations = searchResponse.getAggregations();
Map<String, Aggregation> aggregationMap = aggregations.asMap();
//System.out.println(aggregationMap);
Terms goods_brands = (Terms) aggregationMap.get("goods_brands");
List<? extends Terms.Bucket> buckets = goods_brands.getBuckets();
List brands = new ArrayList();
for (Terms.Bucket bucket : buckets) {
Object key = bucket.getKey();
brands.add(key);
}
for (Object brand : brands) {
System.out.println(brand);
}
}
SpringBoot整合ElasticSearch
1)導包
2)配置
3)代碼
ElasticSearch擴展
集群:把一個項目拆分成多個功能模塊,一個功能模塊代碼,部署到多台服務器,所有服務器完成相同的功能
作用:高可用、負載均衡
分布式:把一個項目拆分成多個功能模塊,每個功能模塊單獨部署到一台服務器,協同完成一個流程
作用:分擔存儲、計算壓力,提升應用響應速度
集群、分布式都是高並發解決方案。
ES集群中相關概念
集群-->(多個)節點(主節點、從節點)-->索引-->主分片、副分片
ES集群自平衡:
集群中某個節點宕機,把該節點的分片,平衡到其他分片;當宕機服務器重啟啟動后,再對分片進行自平衡,把分片
拷貝到新啟動的節點。
ES集群分片參考數據(僅供參考):
分片總數 = 總數據量 / 10G-30G
節點數 = 分片總數 / 1-3
腦裂(普遍集群存在的問題):
概念:在集群中,從節點在選擇主節點時,發生意見分歧,產生了多個主節點
原因:
1)網絡延遲
2)主節點負載過大,節點假死
3)JVM內存回收,節點假死
解決:
1) 使用內網
2) ES-主節點專注負責管理,不處理其他請求
3) ES-JVM內存設置為服務器內存的一半大小
1)索引庫維護
(1)准備數據;
(2)創建索引庫、映射、導入數據;
2)搜索
-------QueryBuilders.-----------
1)term
2)match
3)range
4)bool
-------SearchSourceBuilder-----------
5)page
6)sort
7)highlight
8)aggregation