如何在elastic Search中编写既可以进行AND也可以进行OR操作的查询?

问题描述 投票:0回答:1

我正在尝试实现一个弹性搜索查询,它可以执行这样的搜索

在这里,我希望如果我在API的请求正文中传递externalStudentId、DOB和FirstName,那么它必须返回所有具有此externalStudentId的学生网络,无论其DOB如何,以及具有此(DOB AND(FirstName || LastName | | 电子邮件))。

如果仅通过了 DOB 和ExternalStudentId,则所有具有给定externalStudentID 的学生 无论他们的出生日期以及所有具有特定出生日期的学生。

externalStudentId OR (DOB&firstName) OR (DOB&LastName) OR (DOB&Email)

但是我的这段代码不是这样工作的,如果我完全传递 externalStudentID 或 DOB&FirstName 那么它仍然会搜索所有具有不同 FirstName 的学生。

public List<Student> searchStudent(SearchStudentRequest request) {
        List<Student> result = new ArrayList<Student>();
        try {
            SearchResponse<Student> response = osClient.search(s -> s
                            .index(indexName).size(recordSize)
                            .query(q -> q
                                    .bool(b -> {request.encryptValue(this.enc);
                                                Map<String, TermsQuery> t = buildTermQuery(request);
                                                String isShould = !t.isEmpty() && t.size() >= 2 ? "should" : "must";
                                                switch (isShould) {
                                                    case "should":
                                                        b.must(ms -> ms.bool(bq -> {
                                                            for (Map.Entry<String, TermsQuery> entry : t.entrySet()) {
                                                                bq.should(sh -> sh.terms(entry.getValue()));
                                                            }
                                                            bq.minimumShouldMatch("1");
                                                            return bq;
                                                        }));

                                                        break;
                                                    case "must":
                                                    default:
                                                        for (Map.Entry<String, TermsQuery> entry : t.entrySet()) {
                                                            System.out.println(entry);
                                                            b.must(ms -> ms.terms(entry.getValue()));
                                                        }
                                                        break;
                                                }
                                        if(null != request.getDob() && !request.getDob().isBlank()
                                        && request.getExternalStudentId() != null && request.getExternalStudentId().length > 0
                                                && request.getStudentType().equalsIgnoreCase(Constants.STUDENT_TYPES.SRG.toString())) {
                                            b.should(ms->ms.match(QueryBuilders.match().field("dob").query(tq -> tq.stringValue(request.getDob())).build()));
                                            isShould = "should";
                                            b.should(ms -> ms.nested(buildExternalStudentIdTermQuery(request.getExternalStudentId()).build()));
                                            for (MatchQuery m : buildMatchQuery(request)) {
                                                System.out.println(m);
                                                isShould = "should";
                                                b.should(ms -> ms.match(m));
                                            }
                                            if (isShould.equals("should")) {
                                                b.minimumShouldMatch("1");
                                            }

                                            if (request.getStudentType() != null) {
                                                b.must(buildStudentTypeMatchQuery(request.getStudentType())._toQuery());
                                            }

                                            return b;

                                        }
                                        else if (request.getExternalStudentId() != null && request.getExternalStudentId().length > 0
                                                && request.getStudentType().equalsIgnoreCase(Constants.STUDENT_TYPES.SAS.toString()))
                                        {
                                            isShould = "should";
                                            b.should(ms -> ms.terms(buildChannelExternalStudentIdTermQuery(request.getExternalStudentId())));
                                        }
                                        else if (request.getExternalStudentId() != null && request.getExternalStudentId().length > 0
                                                && request.getStudentType().equalsIgnoreCase(Constants.STUDENT_TYPES.SRG.toString()))
                                        {
                                            isShould = "should";
                                            b.should(ms -> ms.nested(buildExternalStudentIdTermQuery(request.getExternalStudentId()).build()));
                                        }

                                        if(null != request.getDob() && !request.getDob().isBlank()) {
                                            b.must(ms->ms.match(QueryBuilders.match().field("dob").query(tq -> tq.stringValue(request.getDob())).build()));
                                        }
                                        for (MatchQuery m : buildMatchQuery(request)) {
                                            System.out.println(m);
                                            isShould = "should";
                                            b.should(ms -> ms.match(m));
                                        }
                                                if (isShould.equals("should")) {
                                                    b.minimumShouldMatch("1");
                                                }

                                                if (request.getStudentType() != null) {
                                                    b.must(buildStudentTypeMatchQuery(request.getStudentType())._toQuery());
                                                }

                                                return b;
                                            }
                                    )
                            )
                    , Student.class);
}
private List<MatchQuery> buildMatchQuery(SearchStudentRequest request) {
        List<MatchQuery> matchQuery = new ArrayList<MatchQuery>();

        if (null != request.getFirstName() && !request.getFirstName().isBlank()) {
            matchQuery.add(QueryBuilders.match().field("firstName").query(t -> t.stringValue(request.getFirstName())).build());
        }
        if (null != request.getLastName() && !request.getLastName().isBlank()) {
            matchQuery.add(QueryBuilders.match().field("lastName").query(t -> t.stringValue(request.getLastName())).build());
        }
        if (null != request.getEmail() && !request.getEmail().isBlank()) {
            matchQuery.add(QueryBuilders.match().field("email").query(t -> t.stringValue(request.getEmail())).build());
        }
        return matchQuery;
    }


需要帮助重构此代码

java spring-boot elasticsearch elastic-stack
1个回答
0
投票

为了重构您的 Elasticsearch 查询实现以支持基于提供的条件进行搜索的 AND 和 OR 操作,这是我简化和组织代码的尝试。我不知道您的具体用例或上下文,并且此代码未经测试,因此使用风险自负。这是 searchStudent 方法的修订版本:

public List<Student> searchStudent(SearchStudentRequest request) {
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    
    // Add externalStudentId condition
    if (request.getExternalStudentId() != null && request.getExternalStudentId().length > 0) {
        boolQuery.should(QueryBuilders.termsQuery("externalStudentId", request.getExternalStudentId()));
    }
    
    // Add DOB condition
    if (request.getDob() != null && !request.getDob().isBlank()) {
        boolQuery.must(QueryBuilders.matchQuery("dob", request.getDob()));
    }
    
    // Add conditions for FirstName, LastName, and Email
    if (request.getFirstName() != null && !request.getFirstName().isBlank()) {
        boolQuery.should(QueryBuilders.matchQuery("firstName", request.getFirstName()));
    }
    if (request.getLastName() != null && !request.getLastName().isBlank()) {
        boolQuery.should(QueryBuilders.matchQuery("lastName", request.getLastName()));
    }
    if (request.getEmail() != null && !request.getEmail().isBlank()) {
        boolQuery.should(QueryBuilders.matchQuery("email", request.getEmail()));
    }
    
    // Add StudentType condition
    if (request.getStudentType() != null) {
        boolQuery.must(QueryBuilders.matchQuery("studentType", request.getStudentType()));
    }
    
    // Perform the search
    SearchResponse<Student> response = osClient.search(s -> s
        .index(indexName)
        .size(recordSize)
        .query(q -> q.bool(b -> b
            .should(boolQuery)
            .minimumShouldMatch(1) // At least one should clause must match
        ))
    , Student.class);
    
    // Extract and return the result
    return response.getHits().getHits().stream()
        .map(SearchHit::getSourceAsObject)
        .map(student -> (Student) student)
        .collect(Collectors.toList());
}

在这个重构版本中:

  1. 使用 BoolQueryBuilder 构造布尔查询以组合多个条件。
  2. 为 externalStudentId、dob、firstName、lastName 和 email 添加了单独的条件。
  3. 使用 should 子句组合所有条件,以针对上述条件执行 OR 运算。
  4. 对 dob 和 StudentType 使用必须子句,以确保文档必须符合这些条件。
  5. 利用minimumShouldMatch(1)来确保至少一个should子句必须匹配。

即使代码最终没有成功,您仍然可以使用上面的列表根据您的需要自行重构代码。

© www.soinside.com 2019 - 2024. All rights reserved.