blob: 32573f9fa3d6d0d4f09cba6917112c0fd9b9b7f9 [file] [log] [blame]
package de.ids_mannheim.korap;
import de.ids_mannheim.korap.filter.BooleanFilter;
import de.ids_mannheim.korap.filter.RegexFilter;
import de.ids_mannheim.korap.util.QueryException;
import de.ids_mannheim.korap.util.KorapDate;
import org.apache.lucene.search.Query;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
Todo: WildCardFilter!
Support: delete boolean etc.
Support: supports foundries
*/
/**
* @author Nils Diewald
*
* KorapFilter implements a simple API for creating meta queries
* constituing Virtual Collections.
*/
public class KorapFilter {
private BooleanFilter filter;
// Logger
private final static Logger log = LoggerFactory.getLogger(KorapFilter.class);
// This advices the java compiler to ignore all loggings
public static final boolean DEBUG = false;
public KorapFilter () {
filter = new BooleanFilter();
};
public KorapFilter (JsonNode json) throws QueryException {
filter = this.fromJSON(json, "tokens");
};
protected BooleanFilter fromJSON (JsonNode json, String field) throws QueryException {
BooleanFilter bfilter = new BooleanFilter();
// TODO: THIS UNFORTUNATELY BREAKS TESTS
if (!json.has("@type"))
throw new QueryException(701, "JSON-LD group has no @type attribute");
String type = json.get("@type").asText();
// Single filter
if (type.equals("korap:doc")) {
String key = "tokens";
String valtype = "type:string";
String match = "match:eq";
if (json.has("key"))
key = json.get("key").asText();
if (json.has("type"))
valtype = json.get("type").asText();
// Filter based on date
if (valtype.equals("type:date")) {
if (!json.has("value"))
throw new QueryException(612, "Dates require value fields");
String dateStr = json.get("value").asText();
if (json.has("match"))
match = json.get("match").asText();
// TODO: This isn't stable yet
switch (match) {
case "match:eq":
bfilter.date(dateStr);
break;
case "match:geq":
bfilter.since(dateStr);
break;
case "match:leq":
bfilter.till(dateStr);
break;
};
/*
No good reason for gt or lt
*/
return bfilter;
}
else if (valtype.equals("type:string")) {
if (json.has("match"))
match = json.get("match").asText();
if (match.equals("match:eq")) {
bfilter.and(key, json.get("value").asText());
};
return bfilter;
};
}
// nested group
else if (type.equals("korap:docGroup")) {
if (!json.has("operands") || !json.get("operands").isArray())
throw new QueryException(612, "Groups need operands");
String operation = "operation:and";
if (json.has("operation"))
operation = json.get("operation").asText();
BooleanFilter group = new BooleanFilter();
for (JsonNode operand : json.get("operands")) {
if (operation.equals("operation:and")) {
group.and(this.fromJSON(operand, field));
}
else if (operation.equals("operation:or")) {
group.or(this.fromJSON(operand, field));
}
else {
throw new QueryException(613, "Unknown document group operation");
};
};
bfilter.and(group);
return bfilter;
}
// UNknown type
else {
throw new QueryException(613, "Collection query type has to be doc or docGroup");
};
return new BooleanFilter();
};
/*
String type = json.get("@type").asText();
String field = _getField(json);
if (type.equals("korap:term")) {
this.fromJSON(json, field);
}
else if (type.equals("korap:group")) {
// TODO: relation
for (JsonNode operand : json.get("operands")) {
this.fromJSON(operand, field);
};
};
*/
// };
protected BooleanFilter fromJSONLegacy (JsonNode json, String field) throws QueryException {
BooleanFilter bfilter = new BooleanFilter();
if (!json.has("@type"))
throw new QueryException(612, "JSON-LD group has no @type attribute");
String type = json.get("@type").asText();
if (DEBUG)
log.trace("@type: " + type);
if (json.has("@field"))
field = _getFieldLegacy(json);
if (type.equals("korap:term")) {
if (field != null && json.has("@value"))
bfilter.and(field, json.get("@value").asText());
return bfilter;
}
else if (type.equals("korap:group")) {
if (!json.has("relation"))
throw new QueryException(612, "Group needs relation");
if (!json.has("operands"))
throw new QueryException(612, "Group needs operand list");
//return bfilter;
String dateStr, till;
JsonNode operands = json.get("operands");
if (!operands.isArray())
throw new QueryException(612, "Group needs operand list");
if (DEBUG)
log.trace("relation found {}", json.get("relation").asText());
BooleanFilter group = new BooleanFilter();
switch (json.get("relation").asText()) {
case "between":
dateStr = _getDateLegacy(json, 0);
till = _getDateLegacy(json, 1);
if (dateStr != null && till != null)
bfilter.between(dateStr, till);
break;
case "until":
dateStr = _getDateLegacy(json, 0);
if (dateStr != null)
bfilter.till(dateStr);
break;
case "since":
dateStr = _getDateLegacy(json, 0);
if (dateStr != null)
bfilter.since(dateStr);
break;
case "equals":
dateStr = _getDateLegacy(json, 0);
if (dateStr != null)
bfilter.date(dateStr);
break;
case "and":
if (operands.size() < 1)
throw new QueryException(612, "Operation needs at least two operands");
for (JsonNode operand : operands) {
group.and(this.fromJSONLegacy(operand, field));
};
bfilter.and(group);
break;
case "or":
if (operands.size() < 1)
throw new QueryException(612, "Operation needs at least two operands");
for (JsonNode operand : operands) {
group.or(this.fromJSONLegacy(operand, field));
};
bfilter.and(group);
break;
default:
throw new QueryException(613, "Relation is not supported");
};
}
else {
throw new QueryException(613, "Filter type is not a supported group");
};
return bfilter;
};
private static String _getFieldLegacy (JsonNode json) {
if (!json.has("@field"))
return (String) null;
String field = json.get("@field").asText();
return field.replaceFirst("korap:field#", "");
};
private static String _getDateLegacy (JsonNode json, int index) {
if (!json.has("operands"))
return (String) null;
if (!json.get("operands").has(index))
return (String) null;
JsonNode date = json.get("operands").get(index);
if (!date.has("@type"))
return (String) null;
if (!date.get("@type").asText().equals("korap:date"))
return (String) null;
if (!date.has("@value"))
return (String) null;
return date.get("@value").asText();
};
public BooleanFilter and (String type, String ... terms) {
BooleanFilter bf = new BooleanFilter();
bf.and(type, terms);
return bf;
};
public BooleanFilter or (String type, String ... terms) {
if (DEBUG)
log.debug("Got some terms here");
BooleanFilter bf = new BooleanFilter();
bf.or(type, terms);
return bf;
};
public BooleanFilter and (String type, RegexFilter re) {
BooleanFilter bf = new BooleanFilter();
bf.and(type, re);
return bf;
};
public BooleanFilter or (String type, RegexFilter re) {
BooleanFilter bf = new BooleanFilter();
bf.or(type, re);
return bf;
};
public BooleanFilter since (String date) {
BooleanFilter bf = new BooleanFilter();
bf.since(date);
return bf;
};
public BooleanFilter till (String date) {
BooleanFilter bf = new BooleanFilter();
bf.till(date);
return bf;
};
public BooleanFilter date (String date) {
BooleanFilter bf = new BooleanFilter();
bf.date(date);
return bf;
};
public BooleanFilter between (String date1, String date2) {
BooleanFilter bf = new BooleanFilter();
bf.between(date1, date2);
return bf;
};
public RegexFilter re (String regex) {
return new RegexFilter(regex);
};
public BooleanFilter getBooleanFilter() {
return this.filter;
};
public void setBooleanFilter (BooleanFilter bf) {
this.filter = bf;
};
public Query toQuery () {
return this.filter.toQuery();
};
public String toString () {
return this.filter.toQuery().toString();
};
};