美文网首页
Java 接入 ElasticSearch

Java 接入 ElasticSearch

作者: 乌鲁木齐001号程序员 | 来源:发表于2020-06-12 18:38 被阅读0次

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;
}

相关文章

网友评论

      本文标题:Java 接入 ElasticSearch

      本文链接:https://www.haomeiwen.com/subject/bphitktx.html