springboot之整合Elasticsearch实现搜索

目录

前言

Elasticsearch是一个基于Lucene的服务器。它提供了在分布式环境下多用户能力的全文搜索引擎,并且它是基于Restful-web接口进行操作。而它的社区地址为中文社区,相应官网地址为客户端,而本次使用的服务器版本为7.6.0

es版本说明

es的版本迭代是非常快的,而其中大的变化如下所示
5.x 一个index->多个type
6.x 一个index->一个type
7.x 移除type,直接操作index
笔者以前工作中使用的是6.x版本,主要基于TransportClient基于连接,采用门面模式去集成es和封装,如下
es
而此次将集成7.x版本,并采用同样的策略,集成es和使用门面模式,是调用者不需要关心实现细节

整合es

最终实现的功能为创建索引,同步与异步批量操作,删除索引以及高亮查询和最基本的CRUD操作

线程池管理

I 增加核心依赖

<properties>
        <es.version>7.8.0</es.version>
    </properties>

 <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${es.version}</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${es.version}</version>
            <scope>compile</scope>
        </dependency>

II RestHighLevelClient连接类

 private static RestHighLevelClient client;

    /**
     * 服务器地址
     */
    private static String host = "your es ip";
    /**
     * 端口
     */
    private static int port = 9200;

    /**
     * 用户名
     */
    private static String user = "";

    /**
     * 密码
     */
    private static String password = "";

    public EsModel() {
        try {
            RestClientBuilder clientBuilder = RestClient
                    .builder(new HttpHost(host, port, "http"));
            if (StringUtils.isNotBlank(user) && StringUtils.isNotBlank(password)) {
                CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, password));
                clientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
                    httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    httpAsyncClientBuilder.setKeepAliveStrategy((resp, context) -> 30);
                    return httpAsyncClientBuilder;
                });
            } else {
                clientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
                    httpAsyncClientBuilder.setKeepAliveStrategy((resp, context) -> 30);
                    return httpAsyncClientBuilder;
                });
            }
            client = new RestHighLevelClient(clientBuilder);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

有了连接之后,就可以实现各种底层api,供上层直接调用

III 创建工厂EsFactory

public class EsFactory extends BasePooledObjectFactory<EsModel> {
    @Override
    public EsModel create() throws Exception {
        return new EsModel();
    }

    @Override
    public PooledObject<EsModel> wrap(EsModel arg0) {
        return new DefaultPooledObject<EsModel>(arg0);
    }

    @Override
    public void destroyObject(PooledObject<EsModel> p) throws Exception {
        p.getObject().close();
        super.destroyObject(p);
    }

}

IV 门面工具类EsUtil
最后的效果通过线程池管理连接,该工具类对外提供封装方法,如下图
工具类

api说明

1 自定义注解
通过自定义注解从而实现配置实体类型,分词规则等

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ES {

    /**
     * @string text ,keyword
     * @Number long, integer, short, byte, double, float, half_float, scaled_float
     * @date date
     * @date_nanos date_nanos
     * @Range integer_range, float_range, long_range, double_range, date_range
     * @binary binary
     * @Nested nested
     */
    String type() default "string";

    /**
     * 分词器选择  0. not_analyzed   1. ik_smart 2. ik_max_word
     */
    int participle() default 0;
}

其它如EsMapping用来存放解析后的实体对象,EsMappingUtils用来解析实体上的注解信息

2 封装查询条件
将可能用到的参数封装到EsParamDto

@Data
public class EsParamDto implements Serializable {
    /**
     * 数据总条数
     */
    private Long total;


    /**
     * 当前页
     */
    private int page = 1;

    /**
     * 每页大小
     */
    private int size = 1;

    /**
     * 是否分页
     */
    private Boolean isPage = true;

    /**
     * 区间查询参数
     */
    private Map<String, RangConditionDTO> rangConditionMap = new HashMap<>();

    /**
     * 时间区间查询参数
     */
    private Map<String, RangConditionsToTimeModelDTO> rangConditionsToTimeModelMap = new HashMap<>();

    /**
     * 模糊相等查询条件,多个查询条件","进行切割
     */
    private Map<String, Object> likeSearchCondition = new HashMap<>();

    /**
     * or条件查询
     */
    private Map<String, Object> orSearchCondition = new HashMap<>();

    /**
     * or条件查询
     */
    private Map<String, Object> orLikeSearchCondition = new HashMap<>();

    /**
     * or条件查询集合类操作
     */
    private List<Map<String, Object>> orSearchConditionList = new ArrayList<>();

    /**
     * 相等查询条件,多个查询条件","进行切割
     */
    private Map<String, Object> equalsSearchCondition = new HashMap<>();

    /**
     * in 查询
     */
    private Map<String, List> inSearchCondition = new HashMap<>();

    /**
     * 模糊不相等的条件,多个查询条件","进行切割
     */
    private Map<String, Object> noLikeSearchConditioin = new HashMap<>();

    /**
     * 不相等的条件,多个查询条件","进行切割
     */
    private Map<String, Object> noEqualsSearchConditioin = new HashMap<>();

    /**
     * 为空过滤
     */
    private List<String> isNullConditioin = new ArrayList<>();

    /**
     * 不为空过滤
     */
    private List<String> isNotNullConditioin = new ArrayList<>();

    /**
     * 排序字段,关键字asc,desc
     */
    private Map<String, String> sortFileds = new LinkedHashMap<>();

    /**
     * 排序字段集合,方便对排序顺序的控制 关键字asc,desc
     */
    private List<Map<String, String>> sortFiledsList = new ArrayList<>();

    /**
     * 高亮字段
     */
    private List<String> hightFieldList = new ArrayList<>();

    /**
     * 去重字段
     */
    private String collapseField;

    /**
     * 指定查询结果包含的字段
     */
    private String[] fetchSourceIncludes;

    /**
     * 指定查询结果不包含的字段
     */
    private String[] fetchSourceExcludes;

    /**
     * 分词字段
     */
    private Map<String, Object> analyzersField = new HashMap<>();

    public String getSortFileds(String key) {
        return sortFileds.get(key);
    }

    public RangConditionDTO getRangConditionMap(String key) {
        return rangConditionMap.get(key);
    }

    public RangConditionsToTimeModelDTO getRangConditionsToTimeModelMap(String key) {
        return rangConditionsToTimeModelMap.get(key);
    }
    
}

其中RangConditionDTO用来区间查询,而RangConditionsToTimeModelDTO用来时间区间查询

3 封装返回数据

@Data
public class PageResult<T> {
    /**
     * 数据总条数
     */
    private Long total;

    /**
     * 当前页
     */
    private int page;

    /**
     * 每页大小
     */
    private int size;


    /**
     * 数据
     */
    private List<T> rows;
}

而底层api实现细节可参考EsModel的方法实现细节

码上有戏

组织结构

测试

新建EsTestModel作为mapping的类

@Data
public class EsTestModel implements Serializable {

    private String id;

    private String userName;

    private String password;

    @ES(type = "integer")
    private int age;
}

可通过注解@ES去建立映射关系

1 测试批量新增
浏览器输入http://localhost:8080/init

 @RequestMapping("/init")
    public boolean init() {
        String index = "test";
        List<EsTestModel> list = new ArrayList<>();
        EsTestModel po = null;
        for (int i = 0; i < 10; i++) {
            po = new EsTestModel();
            po.setId(i + "");
            po.setUserName("admin" + i);
            po.setAge(i);
            list.add(po);
        }
        String paramListJson = JSON.toJSONString(list);
        boolean b = EsUtil.addBatch(index, "id", paramListJson, EsTestModel.class);
        return b;
    }

执行上述代码,打开kabana里的dev模式,进行数据查看
输入GET test/_search?pretty

结果

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "0",
        "_score" : 1.0,
        "_source" : {
          "id" : "0",
          "userName" : "admin0",
          "age" : 0
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : "1",
          "userName" : "admin1",
          "age" : 1
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "id" : "2",
          "userName" : "admin2",
          "age" : 2
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "id" : "3",
          "userName" : "admin3",
          "age" : 3
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "id" : "4",
          "userName" : "admin4",
          "age" : 4
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "id" : "5",
          "userName" : "admin5",
          "age" : 5
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 1.0,
        "_source" : {
          "id" : "6",
          "userName" : "admin6",
          "age" : 6
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "7",
        "_score" : 1.0,
        "_source" : {
          "id" : "7",
          "userName" : "admin7",
          "age" : 7
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "8",
        "_score" : 1.0,
        "_source" : {
          "id" : "8",
          "userName" : "admin8",
          "age" : 8
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "9",
        "_score" : 1.0,
        "_source" : {
          "id" : "9",
          "userName" : "admin9",
          "age" : 9
        }
      }
    ]
  }
}

2 测试更新操作
浏览器输入http://localhost:8080/update

  @RequestMapping("/update")
    public boolean update() {
        String index = "test";
        String id = "0";
        EsTestModel po = new EsTestModel();
        po.setAge(100);
        po.setUserName("slycmiaoxi");
        String paramJson = JSON.toJSONString(po);
        boolean b = EsUtil.update(index, id, paramJson);
        return b;
    }

客户端输入图示请求,结果如下所示

在这里插入图片描述
3 测试高亮显示
浏览器输入http://localhost:8080/query

 @RequestMapping("/query")
    public String query() {
        EsParamDto dto = new EsParamDto();
        dto.setIsPage(true);
        dto.setTotal(3L);
        Map<String, Object> equalsSearchCondition = new HashMap<>();
        equalsSearchCondition.put("id", 1);
        dto.setEqualsSearchCondition(equalsSearchCondition);
        List<String> hightFieldList = new ArrayList<>();
        hightFieldList.add("age");
        dto.setHightFieldList(hightFieldList);
        PageResult result = EsUtil.query(dto, "test");
        return result.toString();
    }

返回结果

PageResult(total=1, page=0, size=1, rows=[{item=1, id=1, userName=admin1, age=1}])

源码地址

github地址

参考文章
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值