ElasticSearch(ES)详解(三)
前言
这章主要详细介绍ES的批量操作、滚动、复合查询等高级操作。
一、ES批量操作
当批量导入数据时,若每条数据都访问一次ES服务器,会造成很大没必要的负担,因此ES提供了Bulk操作,将所有操作封装在一个请求里,一次提交。
(一)Bulk操作
1.控制台操作:
POST _bulk
# 注意在create/update数据输入时千万不要分行,会报错
{"create":{"_index":"student1"}}
{"name":"张三","age":15,"address":"重庆渝北"}
{"create":{"_index":"student1","_id":"1"}}
{"name":"李四","age":17,"address":"北京海淀"}
{"update":{"_index":"student1","_id":"1"}}
{"doc":{"age":"29"}}
{"delete":{"_index":"student1","_id":"jbb4xoEBXFE1Oz4fKGla"}}
2.JAVA API操作
1.初始化集群客户端,这里演示一次,下面操作直接使用
package com.db123;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @description:
* @author: DBH123
* @date: 2022/7/4 10:13
*/
@SpringBootTest
public class ElasticSearchTestPro {
private RestHighLevelClient client;
@BeforeAll
public void before() {
// 初始化ES集群客户端
client = new RestHighLevelClient(
RestClient.builder(
// 输入集群主机
// 主机1
new HttpHost(
"node1",
9200,
"http"
),
// 主机2
new HttpHost(
"node2",
9200,
"http"
),
// 主机3
new HttpHost(
"node3",
9200,
"http"
)
)
);
}
}
2.Bulk操作
// bulk
@Test
public void bulkTest() throws IOException {
// 1.创建Bulk请求对象
BulkRequest bulkRequest = new BulkRequest();
// 2.创建需要对文档操作的请求对象, 加入bulk请求对象中
// 2.1 加入文档1
IndexRequest createRequest = new IndexRequest("student1");
String str = "{\"name\":\"JAVA测试\",\"age\":15,\"address\":\"重庆渝北\"}";
createRequest.id("123").source(str , XContentType.JSON);
bulkRequest.add(createRequest);
// 2.2 加入文档2
IndexRequest createRequest1 = new IndexRequest("student1");
HashMap<String, Object> map1 = new HashMap<>();
map1.put("name" , "wlw");
map1.put("age" , 12);
map1.put("address" , "英国");
createRequest1.id("234").source(map1);
bulkRequest.add(createRequest1);
// 2.3 修改文档
HashMap<String, Object> map = new HashMap<>();
map.put("address", "上海浦东");
UpdateRequest updateRequest = new UpdateRequest("student1", "123").doc(map);
bulkRequest.add(updateRequest);
// 2.4 删除文档
DeleteRequest deleteRequest = new DeleteRequest("student1", "234");
bulkRequest.add(deleteRequest);
// 3.提交客户端处理请求
BulkResponse responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
}
记一个出现的异常:java.lang.IllegalArgumentException: The number of object passed must be even but was [1]
出现该异常的原因在修改文档的请求用的Map类型为Map<String , String>,而修改为Map<String , Object>后正常运行。
(二)Curl文件方式导入数据
如果我们想通过文件方式导入大量数据, 则必须在命令行中使用curl了。
完整命令:
$ curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary "@requests";
Content-Type: application/x-ndjson 可以换为Content-Type: application/json
主要我们要修改为@requests , requests为当前目录下的json文件。
二、ES查询操作
下面展示一个查询的完全体:
GET goods/_search
{
"query": {
"query_string": {
"default_field": "FIELD",
"query": "this AND that OR thus"
}
},
"sort": [
{
"FIELD": {
"order": "desc"
}
}
],
"from": 0,
"size": 20,
"aggs": {
"NAME": {
"AGG_TYPE": {
}
}
},
"highlight": {
"fields": {
"title": {
"pre_tags": {}
, "post_tags": {}
}
}
}
}
下面结合这五部分以goods索引为基础进行重点讲解,下面是goods索引映射。
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"
}
}
}
}
(一)查询操作
1.matchAll
查询索引的全部信息。
控制台操作:
GET goods/_search
{
"query": {
"match_all": {}
}
}
Java 代码
@Test
public void matchAll() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件
QueryBuilder query = QueryBuilders.matchAllQuery();
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
2.tremQuery
根据词条匹配,使用该模式,查询条件不进行分词。
控制台操作:
GET goods/_search
{
"query": {
"term": {
"categoryName": {
"value": "手机"
}
}
}
}
Java API 操作:
// term query
@Test
public void termQueryTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型
QueryBuilder query = QueryBuilders.termQuery("categoryName" , "手机");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
3.matchQuery
匹配查询,会将查询条件先进行分词而后逐个查询,将最后结果求并集(这里可以在操作中指定)。
控制台操作:
GET goods/_search
{
"query": {
"match": {
"title": {
"query": "联通手机",
"operator": "and" #确定结果是什么操作 默认or
}
}
}
}
Java API操作
// match
@Test
public void matchTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型
QueryBuilder query = QueryBuilders.matchQuery("title" , "联通手机");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
4.模糊查询
当对搜索条件不清楚的时候可以使用模糊查询。
(1)wildcard查询
可以对查询条件使用通配符,比如“手*”(手后面一个或多个)、“手?”(手后面一个字符),注意:若通配符在前面后引发全文扫描
控制台操作:
GET goods/_search
{
"query": {
"wildcard": {
"categoryName": {
"value": "手*"
}
}
}
}
Java API操作:
// wildcard
@Test
public void wildcardTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型
QueryBuilder query = QueryBuilders.wildcardQuery("title" , "手*");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
(2)正则查询
根据正则表达式条件进行查询。
控制台操作:
GET goods/_search
{
"query": {
"regexp": {
"title": "n[0-9].+"
}
}
}
Java API操作:
// regexp
@Test
public void regexpTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型
QueryBuilder query = QueryBuilders.regexpQuery("title" , "n[0-9].*");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
(3)前缀查询
配置以查询条件开头的文档,对于keyword的支持比较好。
控制台操作:
GET goods/_search
{
"query": {
"prefix": {
"categoryName": "手"
}
}
}
Java API操作:
// prefix
@Test
public void prefixTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型
QueryBuilder query = QueryBuilders.prefixQuery("categoryName" , "手");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
5.范围查询
根据数值的范围进行查询,通常对于数字、日期支持使用。
控制台操作:
GET goods/_search
{
"query": {
"range": {
"createTime": {
"gte": "2015-03-08 20:00:00",
"lte": "2015-03-08 22:00:00"
, "format": "yyyy-MM-dd HH:mm:ss"
, "time_zone": "-06:00"
}
}
}
}
Java API操作
// range
@Test
public void rangeTest() throws IOException, ParseException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型 设置时间上下限
QueryBuilder query = QueryBuilders
.rangeQuery("createTime" )
.format("yyyy-MM-dd HH:mm:ss")
.lt("2015-03-08 22:00:00")
.gt("2015-03-08 20:00:00");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
6.queryString查询
多条件查询,及将查询条件与多个字段进行match匹配,而后求和(可换)。
控制台操作:
GET goods/_search
{
"query": {
"query_string": {
"fields": ["title" , "brandName" , "categoryName"],
"query": "联通手机 and 华为手机",
"default_operator": "AND"
}
}
}
Java API 操作
// query string
@Test
public void queryStringTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型
QueryBuilder query = QueryBuilders.queryStringQuery("联通 And 华为手机")
.field("title")
.field("brandName")
.field("categoryName")
.defaultOperator(Operator.AND);
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
7.布尔查询
也叫脚本查询,他对多个查询进行拼接。
拼接操作有:
•must(and):条件必须成立
•must_not(not):条件必须不成立
•should(or):条件可以成立
•filter:条件必须成立,性能比must高。不会计算得分
**得分:**即条件匹配度,匹配度越高,得分越高
控制台操作:
GET goods/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"categoryName": {
"value": "手机"
}
}
},
{
"range": {
"price": {
"gte": 2000,
"lte": 3000
}
}
}
],
"must_not": [
{
"term": {
"brandName": {
"value": "三星"
}
}
}
]
}
}
}
Java API操作:
// bool string
@Test
public void boolTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件 及选择查询类型 转型为boolQuery类型
BoolQueryBuilder query = QueryBuilders.boolQuery();
// 3.1 添加条件请求
TermQueryBuilder query1 = QueryBuilders.termQuery("categoryName", "手机");
query.must(query1);
// 3.2 添加请求条件
RangeQueryBuilder query2 = QueryBuilders.rangeQuery("price").gt(3000);
query.mustNot(query2);
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
(二)分页控制
ES对查询返回结果是有控制的,默认返回20条,同时自带分页操作。
1.分页
控制台操作:
GET goods/_search
{
"query": {
"match_all": {}
},
"size": 200,
"from": 0
}
Java API操作:
// 分页
@Test
public void pagingTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 2.1 指定分页
sourceBuilder.size(20);
sourceBuilder.from(0);
// 3. 创建查询条件
QueryBuilder query = QueryBuilders.matchAllQuery();
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回结果 具体可以根据控制台返回json字符串操作
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
2.滚动
分页,是每次都去查索引,然后对结果进行分页返回,滚动操作一次性将结果查完,放入缓存,直接从缓存中拿出数据。
控制台操作:
# 第一次查询 注意scroll后面为缓存信息保存时间
GET goods/_search?scroll=1m
{
"query": {
"match_all": {}
},
"size": 10
}
# 第一次scroll操作会返回一个_scroll_id用于下次操作
{
"_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAzYWZ3dzNGctM2pSRS1rLTJvSmk0cTlLZw==",
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
# 利用scroll_id滚动信息
GET _search/scroll?scroll=1m
{
"scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAJ8gWV1RiN0g5aEZRWHlRbXhJdjdnWWlmZw=="
}
Java操作:
// 滚动
@Test
public void scrollTest() throws IOException {
// 0.初始化scrollId
String scrollId = "";
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3. 创建查询条件
QueryBuilder query = QueryBuilders.matchAllQuery();
// 4.指定查询条件
sourceBuilder.query(query);
// 5.判断是否是第一次回滚。
if (scrollId.isEmpty() || scrollId == ""){
// 6.第一次回滚
// 6.1 设置分页大小
sourceBuilder.size(15);
// 6.2 设置回滚快照有效时间
searchRequest.scroll(TimeValue.timeValueMinutes(1));
// 6.3 发起请求
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
// 6.4 返回scrollId
scrollId = response.getScrollId();
}
// 7.不是第一次返回
// 7.1 创建回滚请求
SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
// 7.2 设置有效时间
searchScrollRequest.scroll(TimeValue.timeValueMinutes(1));
// 7.3 开始滚动
SearchResponse response = client.scroll(searchScrollRequest, RequestOptions.DEFAULT);
// 8.输出结果
SearchHits hits = response.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
String sourceAsString = searchHit.getSourceAsString();
Goods goods = JSON.parseObject(sourceAsString, Goods.class);
System.out.println(goods.toString());
}
}
(三)聚合操作
分为桶聚合、指标聚合
•指标聚合:相当于MySQL的聚合函数。max、min、avg、sum等
•桶聚合:相当于MySQL的 group by 操作。不要对text类型的数据进行分组,会失败
。
控制台操作:
# 指标操作
GET goods/_search
{
"query": {
"match_all": {}
},
"aggs": {
# 聚合列别名
"max_price": {
"max": {
"field": "price"
}
}
}
}
# 桶操作
GET goods/_search
{
"query": {
"match_all": {}
},
"aggs": {
"goods_type": {
"terms": {
"field": "categoryName",
# 显示列表的数量
"size": 10
}
}
}
}
# 聚合操作的结果会在返回值最后表示
"aggregations" : {
"goods_type" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 5,
"buckets" : [
{
"key" : "手机",
"doc_count" : 728
},
{
"key" : "平板电视",
"doc_count" : 207
}
]
}
}
Java API操作:
// 聚合
@Test
public void aggTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 2.1 创建聚合对象
AggregationBuilder aggregation = AggregationBuilders
.terms("brand_type")
.field("categoryName")
.size(10);
//2.2 加入聚合对象
sourceBuilder.aggregation(aggregation);
// 3. 创建查询条件
QueryBuilder query = QueryBuilders.matchAllQuery();
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看聚合返回结果
Aggregations aggregations = search.getAggregations();
Map<String, Aggregation> stringAggregationMap = aggregations.asMap();
// 7.1 通过自定义聚合别名获取对象
Terms brand_type = (Terms)stringAggregationMap.get("brand_type");
List<? extends Terms.Bucket> buckets = brand_type.getBuckets();
for (Terms.Bucket bucket : buckets){
System.out.println("key:" + bucket.getKey());
System.out.println("doc_count" + bucket.getDocCount());
}
}
(四)高亮操作
就是将查询条件,前后加入自定内容或标签,而后和匹配词条一起返回。
控制台操作:
GET goods/_search
{
"query": {
"match": {
"title": "手机"
}
},
"highlight": {
"fields": {
"title": {
"pre_tags": "<div>",
"post_tags": "</div>"
},
"categoryName": {
"pre_tags": "<div>",
"post_tags": "</div>"
}
}
}
}
# 会在返回结果每条加一个highlight词条
{
"_index" : "goods",
"_type" : "_doc",
"_id" : "1284053.0",
"_score" : 0.37477988,
"_source" : {
"brandName" : "中国移动",
"categoryName" : "手机",
"createTime" : "2015-03-08 21:28:55",
"id" : 1284053.0,
"price" : 498.0,
"saleNum" : 99999.0,
"spec" : {
"网络" : "联通3G",
"机身内存" : "16G"
},
"title" : "天语 nibiru 老人手机 土星一号 (T1) 白色 联通3G手机"
},
"highlight" : {
"title" : [
"天语 nibiru 老人<div>手机</div> 土星一号 (T1) 白色 联通3G<div>手机</div>"
]
}
},
Java API操作:
// 高亮
@Test
public void highlightTest() throws IOException {
// 1.搜索请求创建
SearchRequest searchRequest = Requests.searchRequest("goods");
// 2.创建查询条件构造器,封装查询、聚合、分页等信息
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 2.1 创建高亮生成器
HighlightBuilder highlightBuilder = new HighlightBuilder();
// 2.2 定义高亮内容
highlightBuilder.field("title");
highlightBuilder.preTags("<tag>");
highlightBuilder.postTags("</tag>");
// 2.3 设置
sourceBuilder.highlighter(highlightBuilder);
// 3. 创建查询条件
QueryBuilder query = QueryBuilders.matchQuery("title" , "手机");
// 4.指定查询条件
sourceBuilder.query(query);
// 5.指定条件构造器
searchRequest.source(sourceBuilder);
// 6.开始查询
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.查看返回高亮结果
SearchHits hits = search.getHits();
long totalNumber = hits.getTotalHits().value;
System.out.println("查询总条数:" + totalNumber);
SearchHit[] hits1 = hits.getHits();
for (SearchHit searchHit : hits1) {
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
System.out.println(highlightFields.get("title").getFragments()[0]);
}
}
(五)排序操作
将结果根据指定字段进行排序。
控制台操作:
GET goods/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": {
"order": "desc"
}
}
]
}
Java API操作,太简单,自己悟吧。
(六)关于时间的操作
ES中默认的时间存储为date格式,里面还是依靠long型( “createTime” : 1425868398000),若是前端传入的是date类型,那么他会date类型存储。但是一般情况下,若前端传入字符串,ES则需对于字符串进行解析,ES有自己支持的时间类型,但是特别注意ES不支持yyyy-MM-dd HH:mm:ss格式
,若要支持,需要在设置mapping的时候指定date解析格式:
"createTime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy年MM月dd日"
},
还要注意,存入ES中的时间需要加上时区信息,因为es计算的时间和我们要相差8小时
因此在导入时:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GTM+8")
private String createTime;
如果利用range范围查询时间 可以利用format来对输入的值进行解析
GET goods/_search
{
"query": {
"range": {
"createTime": {
"gte": "2015-03-08 20:00:00",
"lte": "2015-03-08 22:00:00",
"format": "yyyy-MM-dd HH:mm:ss",
"time_zone": "-06:00" #通过自己试验,-6可以查到
}
}
}
}
三、索引的迁移及别名
由于ES不能更改mapping,所有当有需求对mapping进行修改时,比如将date改为keyword类型,这时只有新建一个索引,并将老的索引进行迁移,且可以对新的索引取别名为老索引名字,这样第三方操作不会变动,下面进行演示:
# 创建索引
PUT index
{
"mappings": {
"properties": {
"time" : {
"type": "date"
}
}
}
}
# 添加数据
POST _bulk
{"create" : {"_index":"index"}}
{"time" : "2012-12-30"}
{"create" : {"_index":"index"}}
{"time" : "2013-11-30"}
{"create" : {"_index":"index"}}
{"time" : "2015-12-13"}
{"create" : {"_index":"index"}}
{"time" : "2020-12-30"}
# 创建修改索引
PUT index_update
{
"mappings": {
"properties": {
"time" : {
"type": "keyword"
}
}
}
}
# 迁移数据
POST _reindex
{
"source": {
"index": "index"
},
"dest": {
"index": "index_update"
}
}
# 删除老索引
DELETE index
# 更改别名
POST index_update/_alias/index