use of org.mycore.parsers.bool.MCRCondition 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.MCRCondition 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.MCRCondition in project mycore by MyCoRe-Org.
the class MCRQLSearchUtils method buildDefaultQuery.
/**
* Search in default search field specified by MCR.SearchServlet.DefaultSearchField
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static MCRQuery buildDefaultQuery(String search, String defaultSearchField) {
String[] fields = defaultSearchField.split(" *, *");
MCROrCondition queryCondition = new MCROrCondition();
for (String fDef : fields) {
MCRCondition condition = new MCRQueryCondition(fDef, "=", search);
queryCondition.addChild(condition);
}
return new MCRQuery(MCRQueryParser.normalizeCondition(queryCondition));
}
use of org.mycore.parsers.bool.MCRCondition in project mycore by MyCoRe-Org.
the class MCRConditionTransformer method handleNotCondition.
@SuppressWarnings("rawtypes")
private static StringBuilder handleNotCondition(MCRNotCondition notCond, Set<String> usedFields) {
MCRCondition child = notCond.getChild();
StringBuilder sb = new StringBuilder();
sb.append("-");
StringBuilder solrQueryString = toSolrQueryString(child, usedFields, true);
stripPlus(solrQueryString);
if (solrQueryString == null || solrQueryString.length() == 0) {
return null;
}
sb.append(solrQueryString);
return sb;
}
use of org.mycore.parsers.bool.MCRCondition in project mycore by MyCoRe-Org.
the class MCRConditionTransformer method buildMergedSolrQuery.
/**
* Builds SOLR query.
*
* Automatically builds JOIN-Query if content search fields are used in query.
* @param sortBy sort criteria
* @param not true, if all conditions should be negated
* @param and AND or OR connective between conditions
* @param table conditions per "content" or "metadata"
* @param maxHits maximum hits
*/
@SuppressWarnings("rawtypes")
public static SolrQuery buildMergedSolrQuery(List<MCRSortBy> sortBy, boolean not, boolean and, HashMap<String, List<MCRCondition>> table, int maxHits, List<String> returnFields) {
List<MCRCondition> queryConditions = table.get("metadata");
MCRCondition combined = buildSubCondition(queryConditions, and, not);
SolrQuery solrRequestQuery = getSolrQuery(combined, sortBy, maxHits, returnFields);
for (Map.Entry<String, List<MCRCondition>> mapEntry : table.entrySet()) {
if (!mapEntry.getKey().equals("metadata")) {
MCRCondition combinedFilterQuery = buildSubCondition(mapEntry.getValue(), and, not);
SolrQuery filterQuery = getSolrQuery(combinedFilterQuery, sortBy, maxHits, returnFields);
solrRequestQuery.addFilterQuery(MCRSolrConstants.JOIN_PATTERN + filterQuery.getQuery());
}
}
return solrRequestQuery;
}
Aggregations