Java代码接入
java接入的方式有三种:
Node接入:java用nodeAPI的方式,以es中一个node节点接入项目。
比如一个es集群有123三个节点,node接入的方式是指java把自己变成一个节点4,因为自己变成了节点,自然可以访问其他节点了。
当然这种方式不适合。自己变成一个节点,就会有分片等es操作,非常重量级。
Transport接入:借助9300端口作为控制层接入集群
就是以一个Transport端口来连接es各个节点,并发送命令用来查询。
http接入:restful的形式
只需要连接任何一个节点,发送http请求就可以了。
这里只介绍rest形式:
加依赖:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.6.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.6.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.1</version>
</dependency>
加配置,这里需要注意的是,有三个节点,连接任何一个都可以
#声明es服务地址
elasticsearch.ip=127.0.0.1:9200
配置类,用于与es连接
@Configuration
public class ElasticsearchRestClient {
@Value("${elasticsearch.ip}")
String ipAddress;
@Bean(name = "highLevelClient")
public RestHighLevelClient highLevelClient(){
String[] address = ipAddress.split(":");
String ip = address[0];
int port = Integer.valueOf(address[1]);
HttpHost httpHost = new HttpHost(ip , port , "http");
return new RestHighLevelClient(RestClient.builder(new HttpHost[]{httpHost}));
}
}
业务代码,这里只写实现方法:
@Override
public List<ShopModel> searchES(BigDecimal longitude, BigDecimal latitude, String keyword, Integer orderby, Integer categoryId, String tags) throws IOException {
SearchRequest searchRequest = new SearchRequest("shop");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("name",keyword));
searchSourceBuilder.timeout(new TimeValue(60 , TimeUnit.SECONDS));
searchRequest.source(searchSourceBuilder);
List<Integer> shopIdsList = new ArrayList<>();
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits){
shopIdsList.add(new Integer(hit.getSourceAsMap().get("id").toString()));
}
List<ShopModel> shopModelList = shopIdsList.stream().map(id -> {
return get(id);
}).collect(Collectors.toList());
return shopModelList;
}
通过调用RestHighLevelClient的search方法,将searchRequest传入,searchRequest中配SearchSourceBuilder,SearchSourceBuilder中配数据参数。查出以后再根据id查数据库,拿到完整数据。
当然,这样的搜索只是最简单的匹配,没有加任何条件,接下来需要添加些条件的话,用highLevelClient就办不到了,我们可以传json字符串,然后整体传输来实现:
@Override
public List<ShopModel> searchES2(BigDecimal longitude, BigDecimal latitude, String keyword, Integer orderby, Integer categoryId, String tags) throws IOException {
SearchRequest searchRequest = new SearchRequest("shop");
List<ShopModel> shopModelList = new ArrayList<>();
Request request = new Request("GET" , "/shop/_search");
String reqJson = "{\n" +
" \"_source\": \"*\", \n" +
" \"script_fields\": {\n" +
" \"distance\": {\n" +
" \"script\": {\n" +
" \"source\": \"haversin(lat,lon,doc['location'].lat,doc['location'].lon)\",\n" +
" \"lang\": \"expression\",\n" +
" \"params\": {\n" +
" \"lat\":" + latitude.toString() + ",\n" +
" \"lon\":" + longitude.toString() + "\n" +
" }\n" +
" }\n" +
" }\n" +
" },\n" +
" \"query\": {\n" +
" \"function_score\": {\n" +
" \"query\": {\n" +
" \"bool\": {\n" +
" \"must\": [\n" +
" {\"match\": {\"name\": {\"query\": \"" + keyword + "\",\"boost\": 0.1}}},\n" +
" {\"term\": {\"seller_disabled_flag\": 0}}\n" +
" ]\n" +
" }\n" +
" },\n" +
" \"functions\": [\n" +
" {\n" +
" \"gauss\":{\n" +
" \"location\":{\n" +
" \"origin\":\"" + latitude.toString() + "," + longitude.toString() + "\",\n" +
" \"scale\":\"100km\",\n" +
" \"offset\":\"0km\",\n" +
" \"decay\":0.5\n" +
" }\n" +
" },\n" +
" \"weight\": 9\n" +
" },\n" +
" {\n" +
" \"field_value_factor\": {\n" +
" \"field\": \"remark_score\"\n" +
" },\n" +
" \"weight\": 0.2\n" +
" },\n" +
" {\n" +
" \"field_value_factor\": {\n" +
" \"field\": \"seller_remark_score\"\n" +
" },\n" +
" \"weight\": 0.1\n" +
" }\n" +
" ],\n" +
" \"score_mode\": \"sum\",\n" +
" \"boost_mode\": \"sum\"\n" +
" }\n" +
" }\n" +
"}";
System.out.println(reqJson);
request.setJsonEntity(reqJson);
Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
String responseStr = EntityUtils.toString(response.getEntity());
System.out.println(responseStr);
JSONObject jsonObject = JSONObject.parseObject(responseStr);
JSONArray jsonArray = jsonObject.getJSONObject("hits").getJSONArray("hits");
for (int i = 0 ; i < jsonArray.size() ; i ++){
JSONObject jsonObj = jsonArray.getJSONObject(i);
Integer id = new Integer(jsonObj.get("_id").toString());
BigDecimal distance = new BigDecimal(jsonObj.getJSONObject("fields").getJSONArray("distance").get(0).toString());
ShopModel shopModel = get(id);
shopModel.setDistance(distance.multiply(new BigDecimal(1000).setScale(0 , BigDecimal.ROUND_CEILING)).intValue());
shopModelList.add(shopModel);
}
return shopModelList;
}
需要注意的是,这里的request和response都是es中的,使用es类底层的传输来进行数据查询。
这样的查询比较死板,如果想调整也非常麻烦,所以可以用object字符串拼接,先上代码:
@Override
public Map<String, Object> searchES3(BigDecimal longitude, BigDecimal latitude, String keyword, Integer orderby, Integer categoryId, String tags) throws IOException {
Map<String, Object> result = new HashMap<>();
Request request = new Request("GET","/shop/_search");
//构建请求
JSONObject jsonRequestObj = new JSONObject();
//构建source部分
jsonRequestObj.put("_source","*");
//构建自定义距离字段
jsonRequestObj.put("script_fields",new JSONObject());
jsonRequestObj.getJSONObject("script_fields").put("distance",new JSONObject());
jsonRequestObj.getJSONObject("script_fields").getJSONObject("distance").put("script",new JSONObject());
jsonRequestObj.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script")
.put("source","haversin(lat, lon, doc['location'].lat, doc['location'].lon)");
jsonRequestObj.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script")
.put("lang","expression");
jsonRequestObj.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script")
.put("params",new JSONObject());
jsonRequestObj.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script")
.getJSONObject("params").put("lat",latitude);
jsonRequestObj.getJSONObject("script_fields").getJSONObject("distance").getJSONObject("script")
.getJSONObject("params").put("lon",longitude);
//构建query
Map<String,Object> cixingMap = analyzeCategoryKeyword(keyword);
boolean isAffectFilter = false;
boolean isAffectOrder = true;
jsonRequestObj.put("query",new JSONObject());
//构建function score
jsonRequestObj.getJSONObject("query").put("function_score",new JSONObject());
//构建function score内的query
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").put("query",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").put("bool",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool").put("must",new JSONArray());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").add(new JSONObject());
//构建match query
int queryIndex = 0;
if(cixingMap.keySet().size() > 0 && isAffectFilter){
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).put("bool",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").put("should", new JSONArray());
int filterQueryIndex = 0;
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.put("match",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.getJSONObject("match").put("name",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.getJSONObject("match").getJSONObject("name").put("query",keyword);
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.getJSONObject("match").getJSONObject("name").put("boost",0.1);
for(String key : cixingMap.keySet()) {
filterQueryIndex++;
Integer cixingCategoryId = (Integer) cixingMap.get(key);
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.put("term", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.getJSONObject("term").put("category_id", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.getJSONObject("term").getJSONObject("category_id").put("value", cixingCategoryId);
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("bool").getJSONArray("should").getJSONObject(filterQueryIndex)
.getJSONObject("term").getJSONObject("category_id").put("boost", 0);
}
}else{
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).put("match",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("match").put("name", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("match").getJSONObject("name").put("query",keyword);
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("match").getJSONObject("name").put("boost",0.1);
}
queryIndex++;
//构建第二个query的条件
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).put("term",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("term").put("seller_disabled_flag",0);
if(tags != null){
queryIndex++;
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).put("term",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("term").put("tags",tags);
}
if(categoryId != null){
queryIndex++;
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).put("term",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONObject("query").getJSONObject("bool")
.getJSONArray("must").getJSONObject(queryIndex).getJSONObject("term").put("category_id",categoryId);
}
//构建functions部分
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").put("functions",new JSONArray());
int functionIndex = 0;
if(orderby == null) {
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("gauss", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("gauss").put("location", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("gauss")
.getJSONObject("location").put("origin", latitude.toString() + "," + longitude.toString());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("gauss")
.getJSONObject("location").put("scale", "100km");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("gauss")
.getJSONObject("location").put("offset", "0km");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("gauss")
.getJSONObject("location").put("decay", "0.5");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("weight", 9);
functionIndex++;
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("field_value_factor", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("field_value_factor")
.put("field", "remark_score");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("weight", 0.2);
functionIndex++;
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("field_value_factor", new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("field_value_factor")
.put("field", "seller_remark_score");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("weight", 0.1);
if(cixingMap.keySet().size() > 0 && isAffectOrder){
for(String key : cixingMap.keySet()){
functionIndex++;
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("filter",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("filter")
.put("term",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("filter")
.getJSONObject("term").put("category_id",cixingMap.get(key));
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("weight",3);
}
}
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").put("score_mode","sum");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").put("boost_mode","sum");
}else{
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").add(new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).put("field_value_factor",new JSONObject());
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").getJSONArray("functions").getJSONObject(functionIndex).getJSONObject("field_value_factor")
.put("field","price_per_man");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").put("score_mode","sum");
jsonRequestObj.getJSONObject("query").getJSONObject("function_score").put("boost_mode","replace");
}
//排序字段
jsonRequestObj.put("sort",new JSONArray());
jsonRequestObj.getJSONArray("sort").add(new JSONObject());
jsonRequestObj.getJSONArray("sort").getJSONObject(0).put("_score",new JSONObject());
if(orderby == null){
jsonRequestObj.getJSONArray("sort").getJSONObject(0).getJSONObject("_score").put("order","desc");
}else{
jsonRequestObj.getJSONArray("sort").getJSONObject(0).getJSONObject("_score").put("order","asc");
}
//聚合字段
jsonRequestObj.put("aggs",new JSONObject());
jsonRequestObj.getJSONObject("aggs").put("group_by_tags",new JSONObject());
jsonRequestObj.getJSONObject("aggs").getJSONObject("group_by_tags").put("terms",new JSONObject());
jsonRequestObj.getJSONObject("aggs").getJSONObject("group_by_tags").getJSONObject("terms").put("field","tags");
String reqJson = jsonRequestObj.toJSONString();
System.out.println(reqJson);
request.setJsonEntity(reqJson);
Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
String responseStr = EntityUtils.toString(response.getEntity());
System.out.println(responseStr);
JSONObject jsonObject = JSONObject.parseObject(responseStr);
JSONArray jsonArr = jsonObject.getJSONObject("hits").getJSONArray("hits");
List<ShopModel> shopModelList = new ArrayList<>();
for(int i = 0; i < jsonArr.size(); i++){
JSONObject jsonObj = jsonArr.getJSONObject(i);
Integer id = new Integer(jsonObj.get("_id").toString());
BigDecimal distance = new BigDecimal(jsonObj.getJSONObject("fields").getJSONArray("distance").get(0).toString());
ShopModel shopModel = get(id);
shopModel.setDistance(distance.multiply(new BigDecimal(1000).setScale(0,BigDecimal.ROUND_CEILING)).intValue());
shopModelList.add(shopModel);
}
List<Map> tagsList = new ArrayList<>();
JSONArray tagsJsonArray = jsonObject.getJSONObject("aggregations").getJSONObject("group_by_tags").getJSONArray("buckets");
for(int i = 0; i < tagsJsonArray.size();i++){
JSONObject jsonObj = tagsJsonArray.getJSONObject(i);
Map<String,Object> tagMap = new HashMap<>();
tagMap.put("tags",jsonObj.getString("key"));
tagMap.put("num",jsonObj.getInteger("doc_count"));
tagsList.add(tagMap);
}
result.put("tags",tagsList);
result.put("shop",shopModelList);
return result;
}
//构造分词函数识别器
private Map<String,Object> analyzeCategoryKeyword(String keyword) throws IOException {
Map<String,Object> res = new HashMap<>();
Request request = new Request("GET","/shop/_analyze");
request.setJsonEntity("{" + " \"field\": \"name\"," + " \"text\":\""+keyword+"\"\n" + "}");
Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
String responseStr = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = JSONObject.parseObject(responseStr);
JSONArray jsonArray = jsonObject.getJSONArray("tokens");
for(int i = 0; i < jsonArray.size(); i++){
String token = jsonArray.getJSONObject(i).getString("token");
Integer categoryId = getCategoryIdByToken(token);
if(categoryId != null){
res.put(token,categoryId);
}
}
return res;
}
private Map<Integer,List<String>> categoryWorkMap = new HashMap<>();
private Integer getCategoryIdByToken(String token){
for(Integer key : categoryWorkMap.keySet()){
List<String> tokenList = categoryWorkMap.get(key);
if(tokenList.contains(token)){
return key;
}
}
return null;
}
可以看出,相当之麻烦,但跟上面的相比,更加灵活,这里主要参考mybatis拼接sql。es的json语句为:
GET /shop/_search
{
"_source": "*",
"script_fields": {
"distance": {
"script": {
"source": "haversin(lat,lon,doc['location'].lat,doc['location'].lon)",
"lang": "expression",
"params": {
"lat":31.306171,
"lon":121.525841
}
}
}
},
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{"match": {"name": {"query": "凯悦","boost": 0.1}}},
{"term": {"seller_disabled_flag": 0}},
{"term": {"tags": "落地大窗"}}
]
}
},
"functions": [
{
"gauss":{
"location":{
"origin":"31.306171,121.525841",
"scale":"100km",
"offset":"0km",
"decay":0.5
}
},
"weight": 9
},
{
"field_value_factor": {
"field": "remark_score"
},
"weight": 0.2
},
{
"field_value_factor": {
"field": "seller_remark_score"
},
"weight": 0.1
}
],
"score_mode": "sum",
"boost_mode": "sum"
}
},
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"aggs": {
"group_by_tags": {
"terms": {
"field": "tags"
}
}
}
}
结果中aggs的结果:会把tags作为一个统计传出来。
虽然麻烦,但是还是可以满足大多数的情况了。