我正在尝试实现一个弹性搜索查询,它可以执行这样的搜索
在这里,我希望如果我在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;
}
需要帮助重构此代码
为了重构您的 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());
}
在这个重构版本中:
即使代码最终没有成功,您仍然可以使用上面的列表根据您的需要自行重构代码。