use of org.mycore.parsers.bool.MCRSetCondition 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.MCRSetCondition 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.MCRSetCondition in project mycore by MyCoRe-Org.
the class MCRQLSearchUtils method buildNameValueQuery.
/**
* Search using name=value pairs from HTTP request
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static MCRQuery buildNameValueQuery(HttpServletRequest req) {
MCRAndCondition condition = new MCRAndCondition();
for (Enumeration<String> names = req.getParameterNames(); names.hasMoreElements(); ) {
String name = names.nextElement();
if (name.endsWith(".operator")) {
continue;
}
if (name.contains(".sortField")) {
continue;
}
if (SEARCH_PARAMETER.contains(name)) {
continue;
}
if (name.startsWith("XSL.")) {
continue;
}
String[] values = req.getParameterValues(name);
MCRSetCondition parent = condition;
if ((values.length > 1) || name.contains(",")) {
// Multiple fields with same name, combine with OR
parent = new MCROrCondition();
condition.addChild(parent);
}
for (String fieldName : name.split(",")) {
String operator = getReqParameter(req, fieldName + ".operator", "=");
for (String value : values) {
parent.addChild(new MCRQueryCondition(fieldName, operator, value));
}
}
}
if (condition.getChildren().isEmpty()) {
throw new MCRUsageException("Missing query condition");
}
return new MCRQuery(MCRQueryParser.normalizeCondition(condition));
}
use of org.mycore.parsers.bool.MCRSetCondition in project mycore by MyCoRe-Org.
the class MCRConditionTransformer method groupConditionsByIndex.
/**
* Build a table from index ID to a List of conditions referencing this
* index
*/
@SuppressWarnings("rawtypes")
public static HashMap<String, List<MCRCondition>> groupConditionsByIndex(MCRSetCondition cond) {
HashMap<String, List<MCRCondition>> table = new HashMap<>();
@SuppressWarnings("unchecked") List<MCRCondition> children = cond.getChildren();
for (MCRCondition child : children) {
String index = getIndex(child);
table.computeIfAbsent(index, k -> new ArrayList<>()).add(child);
}
return table;
}
use of org.mycore.parsers.bool.MCRSetCondition in project mycore by MyCoRe-Org.
the class MCRQLSearchUtils method getSolrQuery.
@SuppressWarnings("rawtypes")
public static SolrQuery getSolrQuery(MCRQuery query, Document input, HttpServletRequest request) {
int rows = Integer.parseInt(input.getRootElement().getAttributeValue("numPerPage", "10"));
List<String> returnFields = query.getReturnFields();
MCRCondition condition = query.getCondition();
HashMap<String, List<MCRCondition>> table;
if (condition instanceof MCRSetCondition) {
table = MCRConditionTransformer.groupConditionsByIndex((MCRSetCondition) condition);
} else {
// if there is only one condition its no set condition. we don't need to group
LOGGER.warn("Condition is not SetCondition.");
table = new HashMap<>();
ArrayList<MCRCondition> conditionList = new ArrayList<>();
conditionList.add(condition);
table.put("metadata", conditionList);
}
boolean booleanAnd = !(condition instanceof MCROrCondition<?>);
SolrQuery mergedSolrQuery = MCRConditionTransformer.buildMergedSolrQuery(query.getSortBy(), false, booleanAnd, table, rows, returnFields);
String mask = input.getRootElement().getAttributeValue("mask");
if (mask != null) {
mergedSolrQuery.setParam("mask", mask);
mergedSolrQuery.setParam("_session", request.getParameter("_session"));
}
return mergedSolrQuery;
}
Aggregations