/* Copyright 2013 Fabian Steeg, hbz. Licensed under the Eclipse Public License 1.0 */ package models.queries; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.MatchQueryBuilder.Operator; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; /** * Superclass for queries on different indexes. * * @author Fabian Steeg (fsteeg) */ public abstract class AbstractIndexQuery { /** * @return The index fields used by this query type */ public abstract List<String> fields(); /** * @param queryString The query string * @return A query builder for this query type and the given query string */ public abstract QueryBuilder build(String queryString); /* Some common author query stuff used both for gnd and lobid-resources: */ QueryBuilder searchAuthor(final String search, Class<?> caller) { QueryBuilder query; final String lifeDates = "\\((\\d+)-(\\d*)\\)"; final Matcher lifeDatesMatcher = Pattern.compile("[^(]+" + lifeDates).matcher(search); if (lifeDatesMatcher.find()) { query = createAuthorQuery(lifeDates, search, lifeDatesMatcher); } else if (search.matches("\\d+(.+)") && caller == Gnd.class) { query = multiMatchQuery(search, fields().toArray(new String[] {})); } else if (search.matches("(http://d-nb\\.info/gnd/)?\\d+.*")) { final String term = search.startsWith("http") ? search : "http://d-nb.info/gnd/" + search; query = multiMatchQuery(term, fields() .subList(4, fields().toArray().length).toArray(new String[] {})); } else { query = nameMatchQuery(search); } return query; } QueryBuilder multiValueMatchQuery(String queryString) { String queryValues = withoutBooleanOperator(queryString); boolean isAndQuery = isAndQuery(queryString); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); for (String q : queryValues.split(",")) { MatchQueryBuilder query = matchQuery(fields().get(0), q); boolQuery = isAndQuery ? boolQuery.must(query) : boolQuery.should(query); } return boolQuery; } /** * @param queryString The query string * @return The given query, without any boolean operator */ public static String withoutBooleanOperator(final String queryString) { return queryString.replaceAll(",AND|,OR", ""); } /** * @param queryString The query string * @return True, if the given query is a boolean AND query */ public static boolean isAndQuery(String queryString) { return queryString.endsWith(",AND"); } private QueryBuilder createAuthorQuery(final String lifeDates, final String search, final Matcher matcher) { /* Search name in name field and birth in birth field: */ final BoolQueryBuilder birthQuery = boolQuery() .must(nameMatchQuery(search.replaceAll(lifeDates, "").trim())) .must(matchQuery(fields().get(1), matcher.group(1))); return matcher.group(2).equals("") ? birthQuery : /* If we have one, search death in death field: */ birthQuery.must(matchQuery(fields().get(2), matcher.group(2))); } private QueryBuilder nameMatchQuery(final String search) { final MultiMatchQueryBuilder query = multiMatchQuery(search, fields().get(0)).operator(Operator.AND); return fields().size() > 3 ? query.field(fields().get(3)) : query; } }