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