Java 接入 ElasticSearch 的三种方式
Node 接入
将 Java 应用作为一个 Node 节点,加入到 ElasticSearch 的集群中,这种方式太重了,不适合 Java 应用。
Transport 接入
基于 Transport 协议和 9300 端口,进行二进制协议层的交互,效率较好,5.0 开始就不用了。
HTTP 接入
5.0 开始推荐的方式,连接 3 个节点中的任何一点,发送 HTTP 请求就可以。
引入 ElasticSearch 的依赖
- 注意版本号要和 ElasticSearch 的版本号一致;
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.3.0</version>
</dependency>
application.properties 中配置 ElasticSearch 相关信息
#申明es服务地址,只配一个就行了
elasticsearch.ip=127.0.0.1:9200
创建配置 ElasticSearch 的 Bean
package tech.lixinlei.dianping.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@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}));
}
}
搜索业务流程
- H5 发送 keyword 给 Controller;
- Controller 透传 keyword 到 Service;
- Service 通过 Rest Client 向 ElasticSearch 发送搜索请求;
- ElasticSearch 返回 Service 一个 Document ID;
- Service 拿着 Document ID 到 MySQL 中查询门店信息,完了组成成一个完整的实体,返回给 H5;
Java 接入 ElasticSearch 的大致流程
- 先在 Kibana 的 Dev Tools 中编写 Query DSL;
- 再用 JSON 的 API 把 Query DSL 组成起来;
- 最后调用 ElasticSearch 的 Java API 完成搜索请求的发送;
Java 组装 Query DSL | 举个栗子
- 其实就是把 搜索模型的建立 中的几个 Query DSL 用 if ... else ... 的逻辑给组装在一起了;
- 写的时候有个小技巧,在 Dev Tools 中,把 DSL 全折起来,拼一个,打开一个;
@Override
public Map<String, Object> searchES(BigDecimal longitude,
BigDecimal latitude,
String keyword,
Integer orderby,
Integer categoryId,
String tags) throws IOException {
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
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());
//构建第一个 query 的条件
int queryIndex = 0;
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);
//构建第二个 query 的条件
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("seller_disabled_flag", 0);
// 页面传来的有 catetory_id 字段
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);
}
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);
}
//构建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);
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 = highLevelClient.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);
}
Map<String, Object> result = new HashMap<>();
result.put("tags", tagsList);
result.put("shop", shopModelList);
return result;
}
网友评论