基于RestHighLevelClient的Elasticsearch的基本使用

这是RestHighLevelClient的一些使用方式和笔记;

一、版本选择
版本的选择一定要慎!Es的版本,ik的版本,以及高级客户端的包的版本一定要统一,不得不说兼容上还是做得很差的。版本的API差异还是很大。会导致一些问题例如NoSuchMethodInvoce的异常等等。
附上maven

      <!--elasticSearch-->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.2.0</version>
        </dependency>

二、创建客户端
官方文档一定是最有用的东西,附上地址 https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-create-index.html。 (注:以下方式都是采用官方文档的方式,版本可根据自己使用来选择)

properties配置

#elasticsearch配置
elastic-search.clusterName=
elastic-search.hostName=宿主机地址
elastic-search.port=宿主机端口
elastic-search.indices=
elastic-search.types=

ElasticSearchConfig 代码


@Data
@ConfigurationProperties(prefix = "elastic-search")
@Configuration
public class ElasticSearchConfig {

    //ES集群名,默认值
    private String clusterName;

    //ES集群中节点的域名或IP
    private String hostName;

    //ES连接端口号
    private Integer port;

    //ES查询的索引名称
    private String indices;

    //ES查询的Types
    private String types;
}

注入客户端

@Configuration
public class ElasticsearchBean {

    private final ElasticSearchConfig esConfig;

    @Autowired
    public ElasticsearchBean(ElasticSearchConfig esConfig) {
        this.esConfig = esConfig;
    }

    /**
     * @return 封装 RestClient
     */
    @Bean(destroyMethod = "close")
    public RestHighLevelClient restHighLevelClient(){
        return new RestHighLevelClient(RestClient.builder(new HttpHost(esConfig.getHostName(), esConfig.getPort(), "http")));
    }
}

@Bean(destroyMethod = “close”) 及时关闭资源非常重要,曾经遇到过不关闭资源导致整个服务器崩溃的问题

三、创建索引
有三种创建索引的方法:

这是ES使用HTTP的方式创建的列子

curl -XPOST http://localhost:9200/index/_mapping -H 'Content-Type:application/json' -d'
{
        "properties": {
            "content": {
                "type": "text",
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_smart"
            }
        }

}'

首先第一种以Map创建的方式

  		//CreateIndexRequest 实例, 需要注意包的版本 我这里用的7.2的版本 org.elasticsearch.client.indices;
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        //封装属性 类似于json格式
        Map<String, Object> jsonMap = new HashMap<>();
        Map<String, Object> properties = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
        content.put("type", "integer");
        Map<String, Object>account = new HashMap<>();
        content .put("type", "text");
        content .put("analyzer", "ik_max_word");
        properties.put("id", content);
        properties.put("account", account);
        jsonMap.put("properties", properties);
        //设置分片
   		request.settings(Settings.builder()
                .put("index.number_of_shards", 3)
                .put("index.number_of_replicas", 2)
        );
         request.mapping(jsonMap);
         //我使用的同步的方式 异步请参考官方文档
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        if (!createIndexResponse.isAcknowledged()){
            throw new BusinessException("创建索引失败");
        }

第二种使用Builder的方式

  XContentBuilder builder = XContentFactory.jsonBuilder();
        builder.startObject()
                    .startObject("mappings")
                        .startObject("properties")
                            .startObject("id")
                                .field("type", "integer")
                            .endObject()
                            .startObject("account")
                                 .field("type", "text")
                                 .field("analyzer","ik_max_word")
                                 .field("search_analyzer","ik_smart")
                             .endObject()
                        .endObject()
                    .endObject()
                    .startObject("settings")
                        .field("number_of_shards",3)
                         .field("number_of_replicas",1)
                     .endObject()
                .endObject();
        request.mapping(builder); //版本不一样注意这个方法不一样,有些版本是source方法
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        if (!createIndexResponse.isAcknowledged()){
            throw new BusinessException("创建索引失败");
        }

第三种以json的方式

request.mapping(
        "{\n" +
        "  \"properties\": {\n" +
        "    \"message\": {\n" +
        "      \"type\": \"text\"\n" +
        "    }\n" +
        "  }\n" +
        "}", 
        XContentType.JSON);
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        if (!createIndexResponse.isAcknowledged()){
            throw new BusinessException("创建索引失败");
        }

五、数据操作
需要注意的是,从Elasticsearch5.x开始就提出了弱化索引类型-type的使用,起初,我们说"索引"和关系数据库的“库”是相似的,“类型”和“表”是对等的。这是一个不正确的对比,导致了不正确的假设。在关系型数据库里,"表"是相互独立的,一个“表”里的列和另外一个“表”的同名列没有关系,互不影响。但在类型里字段不是这样的。
举个例子,两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。
所以在Elasticsearch7.x就完全去除了type。每个索引的type默认且只有为_doc。

首先是新增

 public void save(User user) throws Exception{
        IndexRequest request = new IndexRequest(INDEX_NAME);
        request.id(user.getId());	//ID也可使用内部自动生成的 不过希望和数据库统一唯一业务ID
        request.source(JSON.toJSONString(user), XContentType.JSON);
     	restHighLevelClient.index(request, RequestOptions.DEFAULT);
    }

获取

    public Object get(String id) {
        GetRequest getRequest = new GetRequest(INDEX_NAME, id);
        GetResponse getResponse = restHighLevelClient.get(getRequest,RequestOptions.DEFAULT);
            if (getResponse.isExists()) {
                String sourceAsString = getResponse.getSourceAsString();
                return sourceAsString;
            }
        return null;
    }

删除

  public void delete(String id) {
       DeleteRequest request = new DeleteRequest(INDEX_NAME, String.valueOf(id));
       DeleteResponse deleteResponse = restHighLevelClient.delete(request,RequestOptions.DEFAULT);
            if (deleteResponse.status() == RestStatus.OK) {
                logger.info("删除成功!id: {}", id);
            }
    }

增删改都非常的简单

基本分页查询

    public Page<User> listPage(Pageable pageable, String coutent) throws Exception{
   	    //创建检索请求
    	SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
   	    //创建搜索构建者
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //设置构建搜索属性
        sourceBuilder.from(pageable.getPageNumber() * pageable.getPageSize()); // 需要注意这里是从多少条开始
        sourceBuilder.size(pageable.getPageSize()); //共返回多少条数据
        sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.ASC)); //根据自己的需求排序

        if (!StringUtils.isEmpty(coutent)){
        //自定义组合查询
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            TermQueryBuilder termQuery = QueryBuilders.termQuery(STATUS, STATUS);
            MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("coutent",coutent)
                    .fuzziness(Fuzziness.AUTO); //模糊匹配
            boolQueryBuilder.must(termQuery).must(queryBuilder);
            sourceBuilder.query(boolQueryBuilder);
        }
    	//传入构建进行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
		//处理结果
        RestStatus restStatus = searchResponse.status();
        if (restStatus != RestStatus.OK){
            throw new BusinessException("搜索错误");
        }
        List<User> list = new ArrayList<>();
        SearchHits hits = searchResponse.getHits();
        hits.forEach(item -> list.add(JSON.parseObject(item.getSourceAsString(), User.class)));
        return new PageImpl<>(list, pageable, hits.getTotalHits().value);
    }

使用QueryBuilder的一些含义

QueryBuilders.termQuery("key", obj) 完全匹配
QueryBuilders.termsQuery("key", obj1, obj2..)   一次匹配多个值
QueryBuilders.matchQuery("key", Obj) 单个匹配, field不支持通配符, 前缀具高级特性
QueryBuilders.multiMatchQuery("text", "field1", "field2"..);  匹配多个字段, field有通配符忒行
QueryBuilders.matchAllQuery();         匹配所有文件

Bool Query 用于组合多个叶子或复合查询子句的默认查询
must 相当于 与 & =
must not 相当于 非 ~ !=
should 相当于 或 | or
filter 过滤

QueryBuilders.boolQuery()
        .must(termQuery("content", "test1"))
        .must(termQuery("content", "test4"))
        .mustNot(termQuery("content", "test2"))
        .should(termQuery("content", "test3"))
        .filter(termQuery("content", "test5"));

高亮查询

    /**
     * 搜索入口 搜索结果处理
     */
    public Page<User> searchContent(Pageable pageable, String content) throws IOException{
        SearchResponse searchResponse = searchHighlight(pageable.getPageSize() * pageable.getPageNumber(), pageable.getPageSize(), content, "account", "name");
        List<User> list = Arrays.stream(searchResponse.getHits().getHits()).map(this::toHighLightUser).collect(Collectors.toList());
        return new PageImpl<>(list, pageable, searchResponse.getHits().getTotalHits().value);
    }

    /**
     * SearchHit 转换为高亮字段对象
     */
    private User toHighLightUser(SearchHit searchHit){
        User user = JSON.parseObject(searchHit.getSourceAsString(), User.class);
        Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
        if (!highlightFields.isEmpty()){
            HighlightField account = highlightFields.get("account");
            if (!StringUtils.isEmpty(account)){
                user.setAccount(Arrays.stream(account.getFragments()).map(Text::string).collect(Collectors.joining("\n")));
            }
            HighlightField name = highlightFields.get("name");
            if (!StringUtils.isEmpty(name)){
                user.setName(Arrays.stream(name.getFragments()).map(Text::string).collect(Collectors.joining("\n")));
            }
        }
        return user;
    }

    /**
     * 构建高亮字段 进行 多字段模糊查询
     */
    private SearchResponse searchHighlight(int from, int size, String content, String ... fields) throws IOException{
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for (String field : fields){
            highlightBuilder.field(makeHighlightContent(field));
        }
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //自定义条件
        boolQueryBuilder.should(QueryBuilders.multiMatchQuery(content, fields).fuzziness(Fuzziness.AUTO));
        boolQueryBuilder.should(QueryBuilders.wildcardQuery("account", "*" + content + "*"));
        boolQueryBuilder.should(QueryBuilders.wildcardQuery("name", "*" + content + "*"));
        return searchDocument(highlightBuilder, boolQueryBuilder , from , size);
    }

    /**
     * 构建SearchRequest, SearchSourceBuilder , 执行search方法
     */
    private SearchResponse searchDocument(HighlightBuilder highlightBuilder, QueryBuilder queryBuilder, int from, int size) throws IOException{
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        if (!ObjectUtils.isEmpty(highlightBuilder)){
            searchSourceBuilder.highlighter(highlightBuilder);
        }
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(size);
        searchRequest.source(searchSourceBuilder);
        return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    /**
     * 封装高亮查询字段
     */
    private HighlightBuilder.Field makeHighlightContent(String fieldName){
        HighlightBuilder.Field highlightContent = new HighlightBuilder.Field(fieldName);
        highlightContent.preTags("<span style=\"color:red\">");
        highlightContent.postTags("</span>");
        return highlightContent;
    }

(后续慢慢更新。。。。。)

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Elasticsearch 是一种开源的搜索引擎,它是基于 Lucene 搜索引擎库构建的。它提供了一个分布式、多租户的全文搜索引擎,可以用于存储、搜索和分析海量数据。 以下是 Elasticsearch基本使用: 1. 安装 Elasticsearch:可以从官方网站下载 Elasticsearch,然后按照指南进行安装。 2. 运行 Elasticsearch:启动 Elasticsearch,可以在命令行中运行 elasticsearch 命令。 3. 创建索引:在 Elasticsearch 中,数据被组织成一个或多个索引。可以使用 PUT 请求创建索引,例如:`PUT /myindex`。 4. 添加文档:将文档添加到索引中,可以使用 POST 请求,例如:`POST /myindex/_doc`。在请求体中指定文档内容。 5. 查询文档:使用 GET 请求查询文档,例如:`GET /myindex/_search?q=test`。这将返回所有包含 "test" 的文档。 6. 删除文档:使用 DELETE 请求删除文档,例如:`DELETE /myindex/_doc/1`。这将删除索引为 "myindex" 中 ID 为 "1" 的文档。 7. 更新文档:使用 POST 请求更新文档,例如:`POST /myindex/_update/1`。在请求体中指定要更新的字段和值。 8. 聚合查询:可以使用聚合查询对文档进行分组和计算。例如:`GET /myindex/_search?size=0&aggs=group_by_country:terms:field:country`,这将返回按照国家分组并计算数量的结果。 以上是 Elasticsearch基本使用,还有很多高级特性可以探索。了解 Elasticsearch 的更多功能和用法,请参阅官方文档。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值