Search in sources :

Example 1 with MCRAndCondition

use of org.mycore.parsers.bool.MCRAndCondition 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;
    }
}
Also used : MCRNotCondition(org.mycore.parsers.bool.MCRNotCondition) MCRSetCondition(org.mycore.parsers.bool.MCRSetCondition) MCRAndCondition(org.mycore.parsers.bool.MCRAndCondition) StringTokenizer(java.util.StringTokenizer) MCRCondition(org.mycore.parsers.bool.MCRCondition) ArrayList(java.util.ArrayList) List(java.util.List)

Example 2 with MCRAndCondition

use of org.mycore.parsers.bool.MCRAndCondition in project mycore by MyCoRe-Org.

the class MCRQueryParser method buildConditions.

/**
 * Builds a new MCRCondition from parsed elements
 *
 * @param field
 *            one or more field names, separated by comma
 * @param oper
 *            the condition operator
 * @param value
 *            the condition value
 * @return
 */
private MCRCondition<Void> buildConditions(String field, String oper, String value) {
    if (field.contains(",")) {
        // Multiple fields in one condition, combine with OR
        StringTokenizer st = new StringTokenizer(field, ", ");
        MCROrCondition<Void> oc = new MCROrCondition<>();
        while (st.hasMoreTokens()) {
            oc.addChild(buildConditions(st.nextToken(), oper, value));
        }
        return oc;
    } else if (field.contains("-")) {
        // date condition von-bis
        StringTokenizer st = new StringTokenizer(field, "- ");
        String fieldFrom = st.nextToken();
        String fieldTo = st.nextToken();
        if (oper.equals("=")) {
            // von-bis = x --> (von <= x) AND (bis >= x)
            MCRAndCondition<Void> ac = new MCRAndCondition<>();
            ac.addChild(buildCondition(fieldFrom, "<=", value));
            ac.addChild(buildCondition(fieldTo, ">=", value));
            return ac;
        } else if (oper.contains("<")) {
            return buildCondition(fieldFrom, oper, value);
        } else {
            // oper.contains( ">" )
            return buildCondition(fieldTo, oper, value);
        }
    } else {
        return buildCondition(field, oper, value);
    }
}
Also used : StringTokenizer(java.util.StringTokenizer) MCROrCondition(org.mycore.parsers.bool.MCROrCondition) MCRAndCondition(org.mycore.parsers.bool.MCRAndCondition)

Example 3 with MCRAndCondition

use of org.mycore.parsers.bool.MCRAndCondition 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));
}
Also used : MCRUsageException(org.mycore.common.MCRUsageException) MCRQueryCondition(org.mycore.services.fieldquery.MCRQueryCondition) MCROrCondition(org.mycore.parsers.bool.MCROrCondition) MCRQuery(org.mycore.services.fieldquery.MCRQuery) MCRSetCondition(org.mycore.parsers.bool.MCRSetCondition) MCRAndCondition(org.mycore.parsers.bool.MCRAndCondition)

Example 4 with MCRAndCondition

use of org.mycore.parsers.bool.MCRAndCondition 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));
}
Also used : MCRQueryCondition(org.mycore.services.fieldquery.MCRQueryCondition) MCROrCondition(org.mycore.parsers.bool.MCROrCondition) MCRNotCondition(org.mycore.parsers.bool.MCRNotCondition) MCRAndCondition(org.mycore.parsers.bool.MCRAndCondition) HashSet(java.util.HashSet) Test(org.junit.Test)

Aggregations

MCRAndCondition (org.mycore.parsers.bool.MCRAndCondition)4 MCROrCondition (org.mycore.parsers.bool.MCROrCondition)3 StringTokenizer (java.util.StringTokenizer)2 MCRNotCondition (org.mycore.parsers.bool.MCRNotCondition)2 MCRSetCondition (org.mycore.parsers.bool.MCRSetCondition)2 MCRQueryCondition (org.mycore.services.fieldquery.MCRQueryCondition)2 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Test (org.junit.Test)1 MCRUsageException (org.mycore.common.MCRUsageException)1 MCRCondition (org.mycore.parsers.bool.MCRCondition)1 MCRQuery (org.mycore.services.fieldquery.MCRQuery)1