ElasticSearch 8.X

好久没有更新文章了,工作之后活成了社畜。想起最近流行的那句话,我想离开浪浪山。。。
累?糊口啊!大哥!
生活仍然要继续。。。
(坚持,努力,奋斗)
ps:以后坚持把一些会的东西写成文档。

之前研究ElasticSearch 8.X的客户端,原本想用SpringBoot的整个方案的,网上搜了一圈没有。GitHub上也说明不支持8.X的版本。所以这边就研究了一下官网给出的Java Client。

ps:先熟悉kibana 的语法,再看接口实现,比较好理解些。

下面给出了一些样例,主要批量的操作。单个的这边就不给出了,大家可以去看官网的文档,或者Github下载Java Client的源码,在Test中会给出demo样例。

(如果写的不好的或者有问题的地方,欢迎大评论)

pom.xml

<dependency>
            <groupId>co.elastic.clients</groupId>
            <artifactId>elasticsearch-java</artifactId>
            <version>8.4.3</version>
<dependency>

application.yml

elasticsearch:
  cluster-nodes: 192.168.105.29:9200

Configuration配置

    @Bean
    public ElasticsearchClient elasticsearchClient() {
        List<String> clusterNodes = elasticsearchProperties.getClusterNodes();
        clusterNodes.forEach(node -> {
            try {
                String[] parts = StringUtils.split(node, ":");
                Assert.notNull(parts, "Must defined");
                Assert.state(parts.length == 2, "Must be defined as 'host:port'");
                httpHosts.add(new HttpHost(parts[0], Integer.parseInt(parts[1])));
            } catch (Exception e) {
                throw new IllegalStateException("Invalid ES nodes " + "property '" + node + "'", e);
            }
        });
        RestClient restClient = RestClient.builder(httpHosts.toArray(new HttpHost[0])).build();
        // Create the transport with a Jackson mapper
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper());

        return new ElasticsearchClient(transport);
    }

@Autowired
    private ElasticsearchClient elasticsearchClient;

精确查询 + 模糊匹配

public static List<Query> getComposeProceQuery(BillComposePrice composePrice, Bill bill, BillRequest request) {
        List<Query> res = new ArrayList<>();
        // TermQurey全匹配
        res.add(TermQuery.of(m -> m.field(EsField.AREA)
                .value(composePrice.getArea()))._toQuery());
        res.add(TermQuery.of(m -> m.field(EsField.BILL_NORM)
                .value(composePrice.getBillNorm()))._toQuery());
        res.add(TermQuery.of(m -> m.field(EsField.BILL_UNIT)
                .value(bill.getBillUnit()))._toQuery());
        // 过滤已删除的
        res.add(TermQuery.of(m -> m.field(EsField.DELETED_FLAG)
                .value(0))._toQuery());

        // 分词匹配
        res.add(MatchQuery.of(m -> m.field(EsField.BILL_PROFEATURE)
                .query(bill.getBillProFeature()))._toQuery());
        return res;
    }
protected List<BillInfo> composePrice(BillRequest request,
                                          String indexName,
                                          BillComposePrice composePrice) throws IOException, ElasticsearchException {
        List<BillInfo> res = new ArrayList<>();
        List<List<Query>> searchQuerys = new ArrayList<>();
        List<Bill> bills = composePrice.getBills();
        for (Bill bill : bills) {
            // 生成查询条件
            searchQuerys.add(getComposeProceQuery(composePrice, bill, request));
        }
        // 查询条件
        List<RequestItem> requestItems = new ArrayList<>();
        for (List<Query> searchQuery : searchQuerys) {
            RequestItem.Builder requestBuilder = new RequestItem.Builder();
            // 设置索引表
            requestBuilder.header(h -> h.index(indexName));
            requestBuilder.body(b -> b.query(q -> q.bool(co -> {
                co.must(searchQuery);
                // 业务逻辑,根据不同条件执行不同的查询
                if (composePrice.getFindInSelfFlag() == 1 && composePrice.getFindInTradeFlag() == 1) {
                    co.must(userq -> userq.bool(userB -> userB.should(
                            TermQuery.of(m -> m.field(EsField.USER)
                                    .value(request.getUser()))._toQuery(),
                            TermQuery.of(m -> m.field(EsField.USER)
                                    .value(GlobalConstant.TRADE_USER))._toQuery()
                    )));
                }
                return co;
            })));
            requestItems.add(requestBuilder.build());
        }
        MsearchRequest.Builder builder = new MsearchRequest.Builder();
        // 批量查询
        List<MultiSearchResponseItem<BillInfo>> responses =
                elasticsearchClient.msearch(builder.searches(requestItems).build(), BillInfo.class).responses();
        // 解析结果
        for (MultiSearchResponseItem<BillInfo> mhit : responses) {
            if (!mhit.isFailure() && mhit.result().hits().hits().size() > 0) {
                List<Hit<BillInfo>> hits = mhit.result().hits().hits();
                // 返回第一个(第一个就是评分最高的那个)
                res.add(hits.get(0).source());
            } else {
                res.add(null);
            }
        }
        return res;
}

批量插入

先检查库中有没有对应数据,有就更新,没有就创建。外加条目数限制。

        // 校验库中是否已存在
        List<List<Query>> sameQuerys = new ArrayList<>();
        for (BillInfo bulkInfo : bulkInfos) {
            sameQuerys.add(EsConditionCreate.findSameQuery(bulkInfo));
        }
        List<MultiSearchResponseItem<BillInfo>> searchResponseItems =
                searchBulk(indexName, sameQuerys).responses();
        int updateCount = 0;
        // 获取相似的ID
        for (int i = 0; i < searchResponseItems.size(); i++) {
            MultiSearchResponseItem<BillInfo> hit = searchResponseItems.get(i);
            if (!hit.isFailure() && hit.result().hits().hits().size() != 0) {
                bulkInfos.get(i).setBillUID(hit.result().hits().hits().get(0).id());
                updateCount++;
            }
        }
        List<BillInfo> loadBulk;
        // 插入条目的限制
        if (createLimit != -1 && bulkInfos.size() - updateCount > createLimit) {
            loadBulk = new ArrayList<>();
            for (BillInfo billInfo : bulkInfos) {
                String billUID = billInfo.getBillUID();
                if (billUID.isEmpty() && createLimit <= 0) {
                    // 创建限制不加入
                    continue;
                } else if (billUID.isEmpty()) {
                    --createLimit;
                }
                loadBulk.add(billInfo);
            }
        } else {
            loadBulk = bulkInfos;
        }
        
        if (loadBulk.size() == 0) {
            throw new BillServerException(ResultCode.UPLOAD_OVER_MAX);
        }
        BulkRequest.Builder br = new BulkRequest.Builder();
        for (BillInfo billInfo : loadBulk) {
            br.operations(op -> op
                    .index(idx -> {
                        idx.index(indexName).document(billInfo);
                        // 相似的,直接覆盖。设置对应id
                        if (!billInfo.getBillUID().isEmpty()) {
                            idx.id(billInfo.getBillUID());
                        }
                        return idx;
                    }));
        }
        // 批量插入
        return elasticsearchClient.bulk(br.build());

批量查询

// 根据条件批量查询
protected MsearchResponse<BillInfo> searchBulk(String indexName, List<List<Query>> searchQuerys)
            throws IOException, ElasticsearchException {
        List<RequestItem> requestItems = new ArrayList<>();
        for (List<Query> searchQuery : searchQuerys) {
            RequestItem.Builder requestBuilder = new RequestItem.Builder();
            requestBuilder.header(h -> h.index(indexName));
            requestBuilder.body(b -> b.query(q -> q.bool(co -> co.must(searchQuery))));
            requestItems.add(requestBuilder.build());
        }
        MsearchRequest.Builder builder = new MsearchRequest.Builder();

        return elasticsearchClient.msearch(builder.searches(requestItems).build(), BillInfo.class);
    }

    /**
     * 批量查询
     *
     * @param searchItems Tuple(id, indexName)
     * @return Tuple(id, indexName, value)
     */
    protected List<Tuple> searchByIdBulk(List<Tuple> searchItems)
            throws IOException, ElasticsearchException {
        List<MultiGetOperation> multiGetOperations = new ArrayList<>();

        for (Tuple searchItem : searchItems) {
            MultiGetOperation multiGetOperation = MultiGetOperation.of(mget -> mget
                    .index(searchItem.get(0)) // indexName
                    .id(searchItem.get(1))); // _id
            multiGetOperations.add(multiGetOperation);

        }

        MgetRequest.Builder builder = new MgetRequest.Builder();
        builder.docs(multiGetOperations);
        List<MultiGetResponseItem<BillInfo>> docs =
                elasticsearchClient.mget(builder.build(), BillInfo.class).docs();
        return getBillInfos(docs);
    }

批量更新

/**
     * 批量更新
     *
     * @param updateList, Tuple(indexName, id, doc)
     */
    protected BulkResponse updateBulk(List<Tuple> updateList)
            throws IOException, ElasticsearchException {
        BulkRequest.Builder br = new BulkRequest.Builder();
        for (Tuple updateItem : updateList) {
            br.operations(op -> op
                    .update(up -> up
                            .index(updateItem.get(0))
                            .id(updateItem.get(1))
                            .action(act -> act.doc(updateItem.get(2)))
                    ));
        }

        return elasticsearchClient.bulk(br.build());
    }

多条件查询

代码实在是太长了

Query finalFindByUser = findByUser;
        List<Map<Query, List<Query>>> finalFindByProfessions = findByProfessions;
        List<Query> finalFindByLockShellNum = findByLockShellNum;
        Query finalFindByTime = findByTime;
        List<Query> finalFindByWildcard = findByWildcard;
        Query finalFindByArea = findByArea;
        Query finalFindByBillNorm = findByBillNorm;
        Query finalFindBydeleteFlag = findBydeleteFlag;
        return elasticsearchClient.search(s -> s
                .index(indexName)
                .query(q -> q
                        .bool(b -> {
                            if (finalFindByUser != null) {
                                b.must(finalFindByUser);
                            }
                            if (finalFindBydeleteFlag != null) {
                                b.must(finalFindBydeleteFlag);
                            }
                            if (isAllSelect) {
                                return b;
                            }
                            if (finalFindByArea != null) {
                                b.must(finalFindByArea);
                            }
                            if (finalFindByBillNorm != null) {
                                b.must(finalFindByBillNorm);
                            }
                            if (finalFindByProfessions != null) {
                                b.must(pro -> pro.bool(
                                        professionQ -> {
                                            for (Map<Query, List<Query>> findByProfession : finalFindByProfessions) {
                                                for (Map.Entry<Query, List<Query>> entry : findByProfession.entrySet()) {
                                                    professionQ.should(professionS -> professionS
                                                            .bool(professionB ->
                                                                    professionB.must(entry.getKey()).should(entry.getValue()))
                                                    );
                                                }
                                            }
                                            professionQ.minimumShouldMatch("1");
                                            return professionQ;
                                        }
                                ));

                            }
                            if (finalFindByTime != null) {
                                b.must(finalFindByTime);
                            }
                            if (finalFindByLockShellNum != null) {
                                b.must(loc -> loc.bool(
                                        professionQ -> professionQ.should(finalFindByLockShellNum)
                                                .minimumShouldMatch("1")));
                            }
                            if (finalFindByWildcard != null) {
                                b.must(loc -> loc.bool(
                                        professionQ -> professionQ.should(finalFindByWildcard)
                                                .minimumShouldMatch("1")));
                            }

                            return b;
                        }))
                // sort by updatetime by aesc
                .sort(sinfo -> sinfo.field(f -> f.field(EsField.UPLOAD_TIME).order(SortOrder.Desc)))
                // 分页查询
                .from((searchRequest.getSectionNum() - 1) * searchRequest.getPerSectionNum())
                .size(searchRequest.getPerSectionNum()), BillInfo.class);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值