RestHighLevelClient是项目中使用ES一定会使用到的类。而且官方文档简单易读,非常推荐直接阅读官方文档。
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-document-index.html?baymax=rec&rogue=rec-1&elektra=guide

ES的安装和IK分词器以及初步集成已经介绍。这里简单介绍基本使用。

基本概念

RestHighLevelClient在官方的介绍中,说到这一种Restful的设计。具体的含义,还是不能明白,但是,简单来说,就是把数据操作按照Http的概念规范进行设计的。
ES可以使用Postman操作和访问数据,也得益于此。并且操作数据时,严格遵守了put\post\delete\get的规范,比如是否幂等这些概念。
RestHighLevelClient,在实际使用时,会发现,他和你使用postman没有区别。更方便的是,它设计了函数式编程的操作,我们使用时,是非常非常方便的!

  • 首先要创建一个put\post\delete\get对应的request。当然,还封装了更多功能的请求体,但本质上还是requst。
  • 其次就是向这个请求体中添加信息。保存,需要设置保存的文档,索引。查询,需要设置查询的内容。这些我们使用postman时,都进行过操作,这里实际上是一样的。
  • 最后就是执行了,相当于postman中的执行requst和接受返回值。
  • 当然,针对返回值,我们可以进行封装,供业务使用。

配置ES地址:

es.host=192.168.147.132
es.port=9200
es.scheme=http

在使用时,直接注入RestHighLevelClient即可。

创建索引

    public void test(){
        //创建索引,也可同时创建多个,在后面加参数即可,自己看源码
        CreateIndexRequest request = new CreateIndexRequest("test");
        CreateIndexResponse createIndexResponse=
                restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
    }

增加一条帖子

    public void saveDiscussPost(DiscussPost post){
	    //创建索引,这里使用了函数式编程,先指定索引,然后设置id,将帖子以Json存入,可以看到非常方便和清晰。
        IndexRequest request= new IndexRequest("discusspost")
                .id(String.valueOf(post.getId())).source(JSON.toJSONString(post), XContentType.JSON);
            
	   //执行并接受响应,这里的reponse的结构和我们在postman中看到的完全一样,使用get就可以取出来!
            IndexResponse response = this.restHighLevelClient.index(request, RequestOptions.DEFAULT);
    }

这里删除使用了查询满足条件的文档删除,因此属于批处理。使用了bulk进行操作。

    public void deleteDiscussPost(DiscussPost post){
        DeleteByQueryRequest requestByQuery=new DeleteByQueryRequest("discusspost")
                .setQuery(new TermQueryBuilder("id", post.getId()));
        BulkByScrollResponse deleteResponse = restHighLevelClient.deleteByQuery(requestByQuery, RequestOptions.DEFAULT);
    }

查当然是重头戏,ES和数据库的区别在于查询!倒序索引、内容匹配,分词查询,内容高亮,都是在这里涉及的!这里只能简单的说明,用法很多,还要结合需求多多看文档。

这个方法展示了当我们在搜索框输入内容时,返回一个分页的,关键词高亮的帖子列表给前端展示的过程。

    public Map<String, Object> searchDiscussPost(String keyword, int current, int limit){
	//创建查询请求
        SearchRequest request = new SearchRequest();

		//由于查询比较复杂,需要单独`使用`SearchSourceBuilder`类进行操作,而不是直接操作requst。
		//仍然使用函数式编程。
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.multiMatchQuery(keyword, "title", "content"))// 查询关键词,并指定查询字段包括帖子中的"title"标题, "content"内容字段。
                .sort(SortBuilders.fieldSort("type").order(SortOrder.DESC))//排序,按帖子的类型、热度、时间排序
                .sort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .from(current)//分页:from=(page-1)*size
                .size(limit)
				/*高亮
				1、HighlightBuilder().field指定要处理的高亮字段,preTags postTag指定高亮次的前后标记
				2、函数式编程,继续指定其他要高亮处理的字段。
				*/
                .highlighter(
                        new HighlightBuilder().field("title").preTags("<em>").postTags("</em>")
                        .field(new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>"))
                );
				
		//绑定请求
        request.source(searchSourceBuilder);

       //执行,但是这里我们发现,放回的内容中,没有
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
 
 
        SearchHits hits = response.getHits();

        //一定要记得处理没查到数据的情况
        if (hits.getTotalHits().value <= 0) {
            return null;
        }

        List<DiscussPost> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            DiscussPost post = new DiscussPost();

            String id = hit.getSourceAsMap().get("id").toString();
            post.setId(Integer.valueOf(id));

            String userId = hit.getSourceAsMap().get("userId").toString();
            post.setUserId(Integer.valueOf(userId));

            String title = hit.getSourceAsMap().get("title").toString();
            post.setTitle(title);

            String content = hit.getSourceAsMap().get("content").toString();
            post.setContent(content);

            String status = hit.getSourceAsMap().get("status").toString();
            post.setStatus(Integer.valueOf(status));

            String createTime = hit.getSourceAsMap().get("createTime").toString();
            post.setCreateTime(new Date(Long.parseLong(createTime)));//valueOf

            String commentCount = hit.getSourceAsMap().get("commentCount").toString();
            post.setCommentCount(Integer.valueOf(commentCount));
            // 处理高亮显示的结果
            HighlightField titleField = hit.getHighlightFields().get("title");
            if (titleField != null) {
                post.setTitle(titleField.getFragments()[0].toString());
            }

            HighlightField contentField = hit.getHighlightFields().get("content");
            if (contentField != null) {
                post.setContent(contentField.getFragments()[0].toString());
            }

            list.add(post);
        }

        Map<String,Object> map=new HashMap<>();
        map.put("posts",list);
        String hitsStr = response.getHits().getTotalHits().toString();
        map.put("hits",response.getHits().getTotalHits().toString().substring(0,hitsStr.indexOf(" ")));
        map.put("score",response.getHits().getMaxScore());

        return map;
    }