Closed
Description
I have developed a system that iteratively creates Criteria based on an account's configurations, and the resulting output generated by the system looks something like this:
Criteria criteria = new Criteria("first").is("hello");
List<Criteria> criterias = new ArrayList<>();
criterias.add(new Criteria().or("second").exists());
List<Criteria> subCriterias = new ArrayList<>();
subCriterias.add(new Criteria("third").exists()
.and(new Criteria("fourth").is("ciao")));
subCriterias.add(new Criteria("third").exists()
.and(new Criteria("fourth").is("hi")));
Criteria result = Criteria.or();
for (Criteria c : criterias) {
result = result.or(c);
}
for (Criteria c : subCriterias) {
result = result.subCriteria(c);
}
criteria = criteria.subCriteria(result);
The issue is that in the subCriteria, I sometimes have to repeat "third-exists" in different subCriteria because one of them might not exist. This means I cannot optimize it into something like (third exists AND (fourth is "ciao" OR fourth is "hi")).
The main problem is that the hashCode()
function only considers the first level, sees that both subCriteria start with "third-exists", and therefore decides not to add the second one to the subCriteria.
I am also attaching a test case in the CriteriaQueryMappingUnitTests
class that reproduces this scenario.
void subCriteriaTest() throws JSONException {
Criteria criteria = new Criteria("first").is("hello");
List<Criteria> criterias = new ArrayList<>();
criterias.add(new Criteria().or("second").exists());
List<Criteria> subCriterias = new ArrayList<>();
subCriterias.add(new Criteria("third").exists()
.and(new Criteria("fourth").is("ciao")));
subCriterias.add(new Criteria("third").exists()
.and(new Criteria("fourth").is("hi")));
Criteria result = Criteria.or();
for (Criteria c : criterias) {
result = result.or(c);
}
for (Criteria c : subCriterias) {
result = result.subCriteria(c);
}
criteria = criteria.subCriteria(result);
CriteriaQuery criteriaQuery = new CriteriaQuery(criteria);
String expected = """
{
"bool": {
"must": [
{
"query_string": {
"default_operator": "and",
"fields": [
"first"
],
"query": "hello"
}
},
{
"bool": {
"should": [
{
"exists": {
"field": "second"
}
},
{
"bool": {
"must": [
{
"exists": {
"field": "third"
}
},
{
"query_string": {
"default_operator": "and",
"fields": [
"fourth"
],
"query": "ciao"
}
}
]
}
},
{
"bool": {
"must": [
{
"exists": {
"field": "third"
}
},
{
"query_string": {
"default_operator": "and",
"fields": [
"fourth"
],
"query": "hi"
}
}
]
}
}
]
}
}
]
}
}""";
mappingElasticsearchConverter.updateQuery(criteriaQuery, Person.class);
var queryString = queryToJson(CriteriaQueryProcessor.createQuery(criteriaQuery.getCriteria()), mapper);
assertEquals(expected, queryString, false);
}