use of org.mycore.parsers.bool.MCRNotCondition in project mycore by MyCoRe-Org.
the class MCRQueryParser method normalizeCondition.
/**
* Normalizes a parsed query condition. AND/OR conditions that just have one
* child will be replaced with that child. NOT(NOT(X)) will be normalized to X.
* (A AND (b AND c)) will be normalized to (A AND B AND C), same for nested ORs.
* AND/OR/NOT conditions with no child conditions will be removed.
* Conditions that use the operator "contains" will be splitted into multiple
* simpler conditions if the condition value contains phrases surrounded
* by '...' or wildcard search with * or ?.
*/
public static MCRCondition<Void> normalizeCondition(MCRCondition<Void> cond) {
if (cond == null) {
return null;
} else if (cond instanceof MCRSetCondition) {
MCRSetCondition<Void> sc = (MCRSetCondition<Void>) cond;
List<MCRCondition<Void>> children = sc.getChildren();
sc = sc instanceof MCRAndCondition ? new MCRAndCondition<>() : new MCROrCondition<>();
for (MCRCondition<Void> child : children) {
child = normalizeCondition(child);
if (child == null) {
} else if (child instanceof MCRSetCondition && sc.getOperator().equals(((MCRSetCondition) child).getOperator())) {
// Replace (a AND (b AND c)) with (a AND b AND c), same for OR
sc.addAll(((MCRSetCondition<Void>) child).getChildren());
} else {
sc.addChild(child);
}
}
children = sc.getChildren();
if (children.size() == 0) {
// Completely remove empty AND condition
return null;
} else if (children.size() == 1) {
// Replace AND with just one child
return children.get(0);
} else {
return sc;
}
} else if (cond instanceof MCRNotCondition) {
MCRNotCondition<Void> nc = (MCRNotCondition<Void>) cond;
MCRCondition<Void> child = normalizeCondition(nc.getChild());
if (child == null) {
// Remove empty NOT
return null;
} else if (child instanceof MCRNotCondition) {
return normalizeCondition(((MCRNotCondition<Void>) child).getChild());
} else {
return new MCRNotCondition<>(child);
}
} else if (cond instanceof MCRQueryCondition) {
MCRQueryCondition qc = (MCRQueryCondition) cond;
if (!qc.getOperator().equals("contains")) {
return qc;
}
// Normalize value when contains operator is used
List<String> values = new ArrayList<>();
StringBuilder phrase = null;
StringTokenizer st = new StringTokenizer(qc.getValue(), " ");
while (st.hasMoreTokens()) {
String value = st.nextToken();
if (// we are within phrase
phrase != null) {
if (// end of phrase
value.endsWith("'")) {
value = phrase + " " + value;
values.add(value);
phrase = null;
} else // in middle of phrase
{
phrase.append(' ').append(value);
}
} else if (// begin of phrase
value.startsWith("'")) {
if (// one-word phrase
value.endsWith("'")) {
values.add(value.substring(1, value.length() - 1));
} else {
phrase = new StringBuilder(value);
}
} else if (// begin of NOT phrase
value.startsWith("-'")) {
if (// one-word phrase
value.endsWith("'")) {
values.add("-" + value.substring(2, value.length() - 1));
} else {
phrase = new StringBuilder(value);
}
} else {
values.add(value);
}
}
MCRAndCondition<Void> ac = new MCRAndCondition<>();
for (String value : values) {
if (value.startsWith("'")) {
ac.addChild(new MCRQueryCondition(qc.getFieldName(), "phrase", value.substring(1, value.length() - 1)));
} else if (value.startsWith("-'")) {
ac.addChild(new MCRNotCondition<>(new MCRQueryCondition(qc.getFieldName(), "phrase", value.substring(2, value.length() - 1))));
} else if (value.contains("*") || value.contains("?")) {
ac.addChild(new MCRQueryCondition(qc.getFieldName(), "like", value));
} else if (// -word means "NOT word"
value.startsWith("-")) {
MCRCondition<Void> subCond = new MCRQueryCondition(qc.getFieldName(), "contains", value.substring(1));
ac.addChild(new MCRNotCondition<>(subCond));
} else {
ac.addChild(new MCRQueryCondition(qc.getFieldName(), "contains", value));
}
}
if (values.size() == 1) {
return ac.getChildren().get(0);
} else {
return ac;
}
} else {
return cond;
}
}
use of org.mycore.parsers.bool.MCRNotCondition in project mycore by MyCoRe-Org.
the class MCRConditionTransformer method getIndex.
/**
* Returns the ID of the index of all fields referenced in this condition.
* If the fields come from multiple indexes, the constant mixed is returned.
*/
@SuppressWarnings("rawtypes")
private static String getIndex(MCRCondition cond) {
if (cond instanceof MCRQueryCondition) {
MCRQueryCondition queryCondition = ((MCRQueryCondition) cond);
String fieldName = queryCondition.getFieldName();
return getIndex(fieldName);
} else if (cond instanceof MCRNotCondition) {
return getIndex(((MCRNotCondition) cond).getChild());
}
@SuppressWarnings("unchecked") List<MCRCondition> children = ((MCRSetCondition) cond).getChildren();
// mixed indexes here!
return children.stream().map(MCRConditionTransformer::getIndex).reduce((l, r) -> l.equals(r) ? l : mixed).get();
}
use of org.mycore.parsers.bool.MCRNotCondition in project mycore by MyCoRe-Org.
the class MCRConditionTransformerTest method testToSolrQueryString.
@Test
public final void testToSolrQueryString() {
HashSet<String> usedFields = new HashSet<>();
MCRQueryCondition inner1 = new MCRQueryCondition("objectType", "=", "mods");
assertEquals("+objectType:\"mods\"", MCRConditionTransformer.toSolrQueryString(inner1, usedFields));
assertTrue("usedFields did not contain 'objectType'", usedFields.contains("objectType"));
MCRQueryCondition inner2 = new MCRQueryCondition("objectType", "=", "cbu");
MCROrCondition<Void> orCond = new MCROrCondition<>(inner1, inner2);
usedFields.clear();
// MCR-973 check for surrounding brackets on single OR query
assertEquals("+(objectType:\"mods\" objectType:\"cbu\")", MCRConditionTransformer.toSolrQueryString(orCond, usedFields));
assertTrue("usedFields did not contain 'objectType'", usedFields.contains("objectType"));
MCRQueryCondition inner3 = new MCRQueryCondition("derCount", ">", "0");
MCRAndCondition<Void> andCondition = new MCRAndCondition<>(orCond, inner3);
usedFields.clear();
assertEquals("+(objectType:\"mods\" objectType:\"cbu\") +derCount:{0 TO *]", MCRConditionTransformer.toSolrQueryString(andCondition, usedFields));
assertTrue("usedFields did not contain 'objectType'", usedFields.contains("objectType"));
assertTrue("usedFields did not contain 'derCount'", usedFields.contains("derCount"));
inner3.setOperator(">=");
assertEquals("+(objectType:\"mods\" objectType:\"cbu\") +derCount:[0 TO *]", MCRConditionTransformer.toSolrQueryString(andCondition, usedFields));
inner3.setOperator("<");
assertEquals("+(objectType:\"mods\" objectType:\"cbu\") +derCount:[* TO 0}", MCRConditionTransformer.toSolrQueryString(andCondition, usedFields));
inner3.setOperator("<=");
assertEquals("+(objectType:\"mods\" objectType:\"cbu\") +derCount:[* TO 0]", MCRConditionTransformer.toSolrQueryString(andCondition, usedFields));
MCRNotCondition<Void> notCond = new MCRNotCondition<>(orCond);
andCondition.getChildren().remove(0);
andCondition.getChildren().add(0, notCond);
assertEquals("-(objectType:\"mods\" objectType:\"cbu\") +derCount:[* TO 0]", MCRConditionTransformer.toSolrQueryString(andCondition, usedFields));
}
Aggregations