Refactoring of KorapQuery
diff --git a/Changes b/Changes
index 3e98af2..e327a80 100644
--- a/Changes
+++ b/Changes
@@ -1,9 +1,10 @@
-0.49.3 2014-01-26
+0.49.3 2014-01-29
- [documentation] Improved documentation for API classes (diewald)
- [documentation] Improved documentation for various queries (margaretha)
- [feature] Added deserialization of SpanSubSpanQueries (margaretha)
- [bugfix] Null filters are now correctly extended (diewald)
- - [cleanup] Refactoring of KorapResult and KorapResponse (diewald)
+ - [cleanup] Refactoring of KorapResult, KorapResponse, KorapQuery,
+ deprecated operation:or in favor of operation:junction (diewald)
0.49.2 2014-12-05
- [documentation] Improved documentation for various queries (margaretha)
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index 89f4492..2e8d299 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -30,14 +30,33 @@
negation terms (and negation subqueries), like
[base=Der]([base=alte]|[base=junge])[base=Mann & p!=ADJA]![base=war | base=lag]
Search for all documents containing "s:Der" and ("s:alte" or "s:junge") and "s:Mann"
-
*/
/**
- * @author Nils Diewald
- *
* KorapQuery implements a simple API for wrapping
- * KorAP Lucene Index specific query classes.
+ * KorAP Lucene Index specific query classes and provides
+ * deserialization of JSON-LD queries.
+ *
+ * Build complex queries.
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanQueryWrapper sqw = (SpanQueryWrapper)
+ * kq.seq(
+ * kq.empty(),
+ * kq.seg(
+ * kq.re("mate/p=N.*"),
+ * kq.re("opennlp/p=N.*")
+ * )
+ * );
+ * </pre></blockquote>
+ *
+ * Deserialize from JSON input.
+ * <blockquote><pre>
+ * SpanQueryWrapper = new KorapQuery("tokens").fromJson("{... JsonString ...}");
+ * </pre></blockquote>
+ *
+ * @author diewald
+ *
*/
public class KorapQuery extends Notifications {
private String field;
@@ -49,841 +68,1036 @@
// This advices the java compiler to ignore all loggings
public static final boolean DEBUG = false;
+ // This is obsolete!
public static final byte
- OVERLAP = SpanWithinQuery.OVERLAP,
- REAL_OVERLAP = SpanWithinQuery.REAL_OVERLAP,
- WITHIN = SpanWithinQuery.WITHIN,
- REAL_WITHIN = SpanWithinQuery.REAL_WITHIN,
- ENDSWITH = SpanWithinQuery.ENDSWITH,
- STARTSWITH = SpanWithinQuery.STARTSWITH,
- MATCH = SpanWithinQuery.MATCH;
+ OVERLAP = SpanWithinQuery.OVERLAP,
+ REAL_OVERLAP = SpanWithinQuery.REAL_OVERLAP,
+ WITHIN = SpanWithinQuery.WITHIN,
+ REAL_WITHIN = SpanWithinQuery.REAL_WITHIN,
+ ENDSWITH = SpanWithinQuery.ENDSWITH,
+ STARTSWITH = SpanWithinQuery.STARTSWITH,
+ MATCH = SpanWithinQuery.MATCH;
private static final int MAX_CLASS_NUM = 255; // 127;
/**
- * Constructs a new base object for query generation.
+ * Constructs a new object for query generation.
+ *
* @param field The specific index field for the query.
*/
public KorapQuery (String field) {
- this.field = field;
- this.json = new ObjectMapper();
+ this.field = field;
+ this.json = new ObjectMapper();
};
+
+ // Private class for korap:boundary objects
+ private class Boundary {
+ public int min, max;
+
+ // Constructor for boundaries
+ public Boundary (JsonNode json, int defaultMin, int defaultMax)
+ throws QueryException {
+
+ // No @type defined
+ if (!json.has("@type")) {
+ throw new QueryException(
+ 701,
+ "JSON-LD group has no @type attribute"
+ );
+ };
+
+ // Wrong @type defined
+ if (!json.get("@type").asText().equals("korap:boundary"))
+ throw new QueryException(702, "Boundary definition is invalid");
+
+ // Set min boundary
+ this.min = json.has("min") ?
+ json.get("min").asInt(defaultMin) :
+ defaultMin;
+
+ // Set max boundary
+ this.max = json.has("max") ?
+ json.get("max").asInt(defaultMax) :
+ defaultMax;
+
+ if (DEBUG)
+ log.trace("Found korap:boundary with {}:{}", min, max);
+ };
+ };
+
+
/**
- * Private class for korap:boundary objects
+ * Deserialize JSON-LD query to a {@link SpanQueryWrapper} object.
+ *
+ * <p>
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanQueryWrapper sqw = kq.fromJson('{"@type":"korap:token","wrap":{' +
+ * '"@type":"korap:term","foundry":"opennlp",' +
+ * '"key":"tree","layer":"orth",' +
+ * '"match":"match:eq"}}'
+ * );
+ * </pre></blockquote>
+ *
+ * @param json String representing the JSON query string.
+ * @return {@link SpanQueryWrapper} object.
+ * @throws QueryException
*/
- private class Boundary {
- public int min, max;
+ public SpanQueryWrapper fromJson (String json) throws QueryException {
+ JsonNode jsonN;
+ try {
+ // Read Json string
+ jsonN = this.json.readValue(json, JsonNode.class);
+ }
- public Boundary (JsonNode json, int defaultMin, int defaultMax) throws QueryException {
+ // Something went wrong
+ catch (IOException e) {
+ String msg = e.getMessage();
+ log.warn("Unable to parse JSON: " + msg.split("\n")[0]);
+ throw new QueryException(621, "Unable to parse JSON");
+ };
- if (!json.has("@type"))
- throw new QueryException(701, "JSON-LD group has no @type attribute");
+ // The query is nested in a parent query
+ if (!jsonN.has("@type") && jsonN.has("query"))
+ jsonN = jsonN.get("query");
- if (!json.get("@type").asText().equals("korap:boundary"))
- throw new QueryException(702, "Boundary definition is invalid");
-
- // Set min boundary
- if (json.has("min"))
- this.min = json.get("min").asInt(defaultMin);
- else
- this.min = defaultMin;
-
- // Set max boundary
- if (json.has("max"))
- this.max = json.get("max").asInt(defaultMax);
- else
- this.max = defaultMax;
-
- if (DEBUG)
- log.trace("Found korap:boundary with {}:{}", min, max);
- };
+ // Deserialize from node
+ return this.fromJson(jsonN);
};
- public SpanQueryWrapper fromJson (String jsonString) throws QueryException {
- JsonNode json;
- try {
- json = this.json.readValue(jsonString, JsonNode.class);
- }
- catch (IOException e) {
- String msg = e.getMessage();
- log.warn("Unable to parse JSON: " + msg.split("\n")[0]);
- throw new QueryException(621, "Unable to parse JSON");
- };
- if (!json.has("@type") && json.has("query"))
- json = json.get("query");
-
- return this.fromJson(json);
- };
-
- // http://fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/fasterxml/jackson/databind/JsonNode.html
+ /**
+ * Deserialize JSON-LD query as a {@link JsonNode} object
+ * to a {@link SpanQueryWrapper} object.
+ *
+ * @param json {@link JsonNode} representing the JSON query string.
+ * @return {@link SpanQueryWrapper} object.
+ * @throws QueryException
+ */
// TODO: Exception messages are horrible!
// TODO: Use the shortcuts implemented in this class instead of the wrapper constructors
- // TODO: Check for isArray()
// TODO: Rename this span context!
public SpanQueryWrapper fromJson (JsonNode json) throws QueryException {
+ int number = 0;
+ if (!json.has("@type"))
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
- int number = 0;
+ // Get @type for branching
+ String type = json.get("@type").asText();
- if (!json.has("@type"))
- throw new QueryException(701, "JSON-LD group has no @type attribute");
+ switch (type) {
+ case "korap:group":
+ return this._groupFromJson(json);
- String type = json.get("@type").asText();
+ case "korap:reference":
+ if (json.has("operation") &&
+ !json.get("operation").asText().equals("operation:focus"))
+ throw new QueryException(712, "Unknown reference operation");
- switch (type) {
-
- case "korap:group":
- SpanClassQueryWrapper classWrapper;
-
- if (!json.has("operation"))
- throw new QueryException(703, "Group expects operation");
-
- String operation = json.get("operation").asText();
-
- if (DEBUG)
- log.trace("Found {} group", operation);
-
- if (!json.has("operands"))
- throw new QueryException(704, "Operation needs operand list");
-
- // Get all operands
- JsonNode operands = json.get("operands");
-
- if (!operands.isArray())
- throw new QueryException(704, "Operation needs operand list");
-
- if (DEBUG)
- log.trace("Operands are {}", operands);
-
- switch (operation) {
-
- case "operation:or":
- SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
- for (JsonNode operand : operands) {
- ssaq.or(this.fromJson(operand));
- };
- return ssaq;
-
- case "operation:position":
-
- if (operands.size() != 2)
- throw new QueryException(705, "Number of operands is not acceptable");
-
- // TODO: Check for operands
- // TODO: LEGACY and not future proof
- String frame = json.has("frame") ?
- json.get("frame").asText() :
- "frame:contains";
-
- if (DEBUG)
- log.trace("Position frame is '{}'", frame);
-
- byte flag = WITHIN;
- switch (frame) {
- case "frame:contains":
- break;
- case "frame:strictlyContains":
- flag = REAL_WITHIN;
- break;
- case "frame:within":
- break;
- case "frame:startswith":
- flag = STARTSWITH;
- break;
- case "frame:endswith":
- flag = ENDSWITH;
- break;
- case "frame:matches":
- flag = MATCH;
- break;
- case "frame:overlaps":
- flag = OVERLAP;
- break;
- case "frame:strictlyOverlaps":
- flag = REAL_OVERLAP;
- break;
- case "":
- // Temporary workaround for wrongly set overlaps
- if (json.has("frames")) {
- frame = json.get("frames").get(0).asText();
- if (frame.equals("frames:overlapsLeft") ||
- frame.equals("frames:overlapsRight")) {
- flag = OVERLAP;
- break;
- };
- };
- default:
- throw new QueryException(706, "Frame type is unknown");
- };
-
- // Check for exclusion modificator
- Boolean exclude;
- if (json.has("exclude") && json.get("exclude").asBoolean())
- throw new QueryException(
- 760,
- "Exclusion is currently not supported in position operations"
- );
-
- return new SpanWithinQueryWrapper(
- this.fromJson(operands.get(0)),
- this.fromJson(operands.get(1)),
- flag
- );
-
- // TODO: This is DEPRECATED and should be communicated that way
- case "operation:submatch":
-
- if (operands.size() != 1)
- throw new QueryException(705, "Number of operands is not acceptable");
-
- if (json.has("classRef")) {
- if (json.has("classRefOp"))
- throw new QueryException(
- 761,
- "Class reference operators are currently not supported"
- );
-
- number = json.get("classRef").get(0).asInt();
- }
- else if (json.has("spanRef")) {
- throw new QueryException(
- 762,
- "Span references are currently not supported"
- );
- };
-
- return new SpanMatchModifyQueryWrapper(
- this.fromJson(operands.get(0)), number
+ if (!json.has("operands")) {
+ throw new QueryException(
+ 766,
+ "Peripheral references are currently not supported"
);
+ };
- case "operation:sequence":
+ JsonNode operands = json.get("operands");
- // Sequence with only one operand
- if (operands.size() == 1)
- return this.fromJson(operands.get(0));
+ if (!operands.isArray())
+ throw new QueryException(704, "Operation needs operand list");
- SpanSequenceQueryWrapper sseqqw = this.seq();
+ if (operands.size() == 0)
+ throw new QueryException(704, "Operation needs operand list");
- // Say if the operand order is important
- if (json.has("inOrder"))
- sseqqw.setInOrder(json.get("inOrder").asBoolean());
+ if (operands.size() != 1)
+ throw new QueryException(705, "Number of operands is not acceptable");
- // Introduce distance constraints
- // ATTENTION: Distances have to be set before segments are added
- if (json.has("distances")) {
-
- // TODO
- if (json.has("exclude") && json.get("exclude").asBoolean())
- throw new QueryException(
- 763,
- "Excluding distance constraints are currently not supported"
- );
-
- if (!json.get("distances").isArray()) {
- throw new QueryException(
- 707,
- "Distance Constraints have " +
- "to be defined as arrays"
- );
- };
-
- // TEMPORARY: Workaround for group distances
- JsonNode firstDistance = json.get("distances").get(0);
-
- if (!firstDistance.has("@type"))
- throw new QueryException(701, "JSON-LD group has no @type attribute");
-
- JsonNode distances;
- if (firstDistance.get("@type").asText().equals("korap:group")) {
- if (!firstDistance.has("operands") ||
- !firstDistance.get("operands").isArray())
- throw new QueryException(704, "Operation needs operand list");
-
- distances = firstDistance.get("operands");
- }
-
- // Support korap distances
- // Support cosmas distances
- else if (
- firstDistance.get("@type").asText().equals("korap:distance")
- ||
- firstDistance.get("@type").asText().equals("cosmas:distance")) {
-
- distances = json.get("distances");
- }
-
- else
- throw new QueryException(708, "No valid distances defined");
-
- // Add all distance constraint to query
- for (JsonNode constraint : distances) {
- String unit = "w";
- if (constraint.has("key"))
- unit = constraint.get("key").asText();
-
- // There is a maximum of 100 fix
- int min = 0, max = 100;
- if (constraint.has("boundary")) {
- Boundary b = new Boundary(constraint.get("boundary"), 0,100);
- min = b.min;
- max = b.max;
- }
- else {
- if (constraint.has("min"))
- min = constraint.get("min").asInt(0);
- if (constraint.has("max"))
- max = constraint.get("max").asInt(100);
- };
-
- // Add foundry and layer to the unit for new indices
- if (constraint.has("foundry") &&
- constraint.has("layer") &&
- constraint.get("foundry").asText().length() > 0 &&
- constraint.get("layer").asText().length() > 0) {
-
- StringBuilder value = new StringBuilder();
- value.append(constraint.get("foundry").asText());
- value.append('/');
- value.append(constraint.get("layer").asText());
- value.append(':').append(unit);
- unit = value.toString();
- };
-
- // Sanitize boundary
- if (max < min)
- max = min;
-
- if (DEBUG)
- log.trace("Add distance constraint of '{}': {}-{}",
- unit, min, max);
-
- sseqqw.withConstraint(min, max, unit);
- };
- };
-
- // Add segments to sequence
- for (JsonNode operand : operands) {
- sseqqw.append(this.fromJson(operand));
- };
-
- // inOrder was set to false without a distance constraint
- if (!sseqqw.isInOrder() && !sseqqw.hasConstraints()) {
- sseqqw.withConstraint(1,1,"w");
- };
-
- return sseqqw;
-
- case "operation:class":
- number = 1;
-
- if (json.has("classOut")) {
- number = json.get("classOut").asInt(0);
- }
- // Legacy classes
- else if (json.has("class")) {
- number = json.get("class").asInt(0);
- };
-
- if (json.has("classRefCheck"))
- this.addWarning(
- 764,
- "Class reference checks are currently not supported - results may not be correct"
+ // Reference based on classes
+ if (json.has("classRef")) {
+ if (json.has("classRefOp")) {
+ throw new QueryException(
+ 761,
+ "Class reference operators are currently not supported"
);
+ };
- if (json.has("classRefOp"))
- throw new QueryException(
- 761,
- "Class reference operators are currently not supported"
+ number = json.get("classRef").get(0).asInt();
+
+
+ if (number > MAX_CLASS_NUM)
+ throw new QueryException(
+ 709,
+ "Valid class numbers exceeded"
);
+ }
- if (number > 0) {
- if (operands.size() != 1)
- throw new QueryException(
- 705,
- "Number of operands is not acceptable"
- );
-
- if (DEBUG)
- log.trace("Found Class definition for {}", number);
-
- if (number > MAX_CLASS_NUM) {
- throw new QueryException(
- 709, "Valid class numbers exceeded"
- );
- };
-
- SpanQueryWrapper sqw = this.fromJson(operands.get(0));
-
- // Problematic
- if (sqw.maybeExtension())
- return sqw.setClassNumber(number);
-
- return new SpanClassQueryWrapper(sqw, number);
- };
-
- throw new QueryException(710, "Class attribute missing");
-
- case "operation:repetition":
-
- if (operands.size() != 1)
- throw new QueryException(
- 705,
- "Number of operands is not acceptable"
- );
-
- int min = 0;
- int max = 100;
-
- if (json.has("boundary")) {
- Boundary b = new Boundary(json.get("boundary"), 0, 100);
- min = b.min;
- max = b.max;
- }
- else {
- if (json.has("min"))
- min = json.get("min").asInt(0);
- if (json.has("max"))
- max = json.get("max").asInt(100);
-
- if (DEBUG)
- log.trace(
- "Boundary is set by deprecated {}-{}",
- min,
- max);
- };
-
- // Sanitize max
- if (max < 0)
- max = 100;
- else if (max > 100)
- max = 100;
-
- // Sanitize min
- if (min < 0)
- min = 0;
- else if (min > 100)
- min = 100;
-
- // Check relation between min and max
- if (min > max)
- max = max;
-
- SpanQueryWrapper sqw = this.fromJson(operands.get(0));
-
- if (sqw.maybeExtension())
- return sqw.setMin(min).setMax(max);
-
- return new SpanRepetitionQueryWrapper(sqw, min, max);
-
- case "operation:relation":
- throw new QueryException(765, "Relations are currently not supported");
- };
-
- throw new QueryException(711, "Unknown group operation");
-
- case "korap:reference":
- if (json.has("operation") &&
- !json.get("operation").asText().equals("operation:focus"))
- throw new QueryException(712, "Unknown reference operation");
-
- if (!json.has("operands"))
- throw new QueryException(
- 766, "Peripheral references are currently not supported"
- );
-
- operands = json.get("operands");
-
- if (!operands.isArray())
- throw new QueryException(704, "Operation needs operand list");
-
- if (operands.size() == 0)
- throw new QueryException(704, "Operation needs operand list");
-
- if (operands.size() != 1)
- throw new QueryException(705, "Number of operands is not acceptable");
-
- if (json.has("classRef")) {
- if (json.has("classRefOp")) {
- throw new QueryException(
- 761,
- "Class reference operators are currently not supported"
- );
- };
-
- number = json.get("classRef").get(0).asInt();
-
-
- if (number > MAX_CLASS_NUM)
- throw new QueryException(
- 709, "Valid class numbers exceeded"
+ // Reference based on spans
+ else if (json.has("spanRef")) {
+ JsonNode spanRef = json.get("spanRef");
+ int length=0;
+ if (!spanRef.isArray() || spanRef.size() == 0) {
+ throw new QueryException(
+ 714,
+ "Span references expect a start position" +
+ " and a length parameter"
);
- }
- else if (json.has("spanRef")) {
- JsonNode spanRef = json.get("spanRef");
- int length=0;
- if (!spanRef.isArray() || spanRef.size() == 0)
- throw new QueryException(714, "Span reference needs a start position and a length parameters.");
+ };
- if (!spanRef.get(1).isMissingNode()){
- length = spanRef.get(1).asInt();
- }
+ if (!spanRef.get(1).isMissingNode())
+ length = spanRef.get(1).asInt();
- return new SpanSubspanQueryWrapper(
+ return new SpanSubspanQueryWrapper(
fromJson(operands.get(0)), spanRef.get(0).asInt(),
- length);
-// throw new QueryException(
-// 762,
-// "Span references are currently not supported"
-// );
- };
+ length
+ );
+ };
- if (DEBUG)
- log.trace("Wrap class reference {}", number);
+ if (DEBUG) log.trace("Wrap class reference {}", number);
- return new SpanMatchModifyQueryWrapper(
- this.fromJson(operands.get(0)), number
- );
+ return new SpanMatchModifyQueryWrapper(
+ this.fromJson(operands.get(0)), number
+ );
- case "korap:token":
+ case "korap:token":
+ // The token is empty and should be treated like []
+ if (!json.has("wrap"))
+ return new SpanRepetitionQueryWrapper();
- // The token is empty and should be treated like []
- if (!json.has("wrap"))
- return new SpanRepetitionQueryWrapper();
+ return this._segFromJson(json.get("wrap"));
- return this._segFromJson(json.get("wrap"));
+ case "korap:span":
+ return this._termFromJson(json);
+ };
- case "korap:span":
- return this._termFromJson(json);
- };
- throw new QueryException(713, "Query type is not supported");
+ // Unknown query type
+ throw new QueryException(713, "Query type is not supported");
+ };
+
+ // Deserialize korap:group
+ private SpanQueryWrapper _groupFromJson (JsonNode json) throws QueryException {
+
+ // No operation
+ if (!json.has("operation"))
+ throw new QueryException(703, "Group expects operation");
+
+ // Get operation
+ String operation = json.get("operation").asText();
+
+ if (DEBUG) log.trace("Found {} group", operation);
+
+ if (!json.has("operands"))
+ throw new QueryException(704, "Operation needs operand list");
+
+ // Get all operands
+ JsonNode operands = json.get("operands");
+
+ if (operands == null || !operands.isArray())
+ throw new QueryException(704, "Operation needs operand list");
+
+ if (DEBUG) log.trace("Operands are {}", operands);
+
+ // Branch on operation
+ switch (operation) {
+ case "operation:junction":
+ return this._operationJunctionFromJson(operands);
+
+ case "operation:position":
+ return this._operationPositionFromJson(json, operands);
+
+ case "operation:sequence":
+ return this._operationSequenceFromJson(json, operands);
+
+ case "operation:class":
+ return this._operationClassFromJson(json, operands);
+
+ case "operation:repetition":
+ return this._operationRepetitionFromJson(json, operands);
+
+ case "operation:relation":
+ throw new QueryException(765, "Relations are currently not supported");
+
+ case "operation:or": // Deprecated in favor of operation:junction
+ return this._operationJunctionFromJson(operands);
+
+ case "operation:submatch": // Deprecated in favor of korap:reference
+ return this._operationSubmatchFromJson(json, operands);
+ };
+
+ // Unknown
+ throw new QueryException(711, "Unknown group operation");
};
+ // Deserialize operation:junction
+ private SpanQueryWrapper _operationJunctionFromJson (JsonNode operands)
+ throws QueryException {
+ SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
+ for (JsonNode operand : operands) {
+ ssaq.or(this.fromJson(operand));
+ };
+ return ssaq;
+ };
+ // Deserialize operation:position
+ private SpanQueryWrapper _operationPositionFromJson (JsonNode json, JsonNode operands)
+ throws QueryException {
+ if (operands.size() != 2)
+ throw new QueryException(705, "Number of operands is not acceptable");
+
+ String frame = "contains";
+ // Temporary workaround for wrongly set overlaps
+ if (json.has("frames")) {
+ JsonNode frameN = json.get("frames");
+ if (frameN.isArray()) {
+ frameN = json.get("frames").get(0);
+ if (frameN != null && frameN.isValueNode())
+ frame = frameN.asText().substring(7);
+ };
+ }
+ // <legacyCode>
+ else if (json.has("frame")) {
+ JsonNode frameN = json.get("frame");
+ if (frameN != null && frameN.isValueNode())
+ frame = frameN.asText().substring(6);
+ };
+ // </legacyCode>
+
+ if (DEBUG) log.trace("Position frame is '{}'", frame);
+
+ // Byte flag - should cover all 13 cases, i.e. two bytes long
+ byte flag = WITHIN;
+ switch (frame) {
+ case "contains":
+ break;
+ case "strictlyContains":
+ flag = REAL_WITHIN;
+ break;
+ case "within":
+ break;
+ case "startswith":
+ flag = STARTSWITH;
+ break;
+ case "endswith":
+ flag = ENDSWITH;
+ break;
+ case "matches":
+ flag = MATCH;
+ break;
+ case "overlaps":
+ flag = OVERLAP;
+ break;
+ case "overlapsLeft":
+ // Temporary workaround
+ this.addWarning(
+ 769,
+ "Overlap variant currently interpreted as overlap"
+ );
+ flag = OVERLAP;
+ break;
+ case "overlapsRight":
+ // Temporary workaround
+ this.addWarning(
+ 769,
+ "Overlap variant currently interpreted as overlap"
+ );
+ flag = OVERLAP;
+ break;
+ case "strictlyOverlaps":
+ flag = REAL_OVERLAP;
+ break;
+ default:
+ throw new QueryException(706, "Frame type is unknown");
+ };
+
+ // The exclusion operator is no longer relevant
+ // <legacyCode>
+ Boolean exclude;
+ if (json.has("exclude") && json.get("exclude").asBoolean()) {
+ throw new QueryException(
+ 760,
+ "Exclusion is currently not supported in position operations"
+ );
+ };
+ // </legacyCode>
+
+ // Create SpanWithin Query
+ return new SpanWithinQueryWrapper(
+ this.fromJson(operands.get(0)),
+ this.fromJson(operands.get(1)),
+ flag
+ );
+ };
+
+ // Deserialize operation:repetition
+ private SpanQueryWrapper _operationRepetitionFromJson (JsonNode json, JsonNode operands)
+ throws QueryException {
+
+ if (operands.size() != 1)
+ throw new QueryException(705, "Number of operands is not acceptable");
+
+ int min = 0;
+ int max = 100;
+
+ if (json.has("boundary")) {
+ Boundary b = new Boundary(json.get("boundary"), 0, 100);
+ min = b.min;
+ max = b.max;
+ }
+ // <legacyCode>
+ else {
+ this.addMessage(0, "Setting boundary by min and max is deprecated");
+
+ // Set minimum value
+ if (json.has("min"))
+ min = json.get("min").asInt(0);
+
+ // Set maximum value
+ if (json.has("max"))
+ max = json.get("max").asInt(100);
+ };
+ // </legacyCode>
+
+ // Sanitize max
+ if (max < 0)
+ max = 100;
+ else if (max > 100)
+ max = 100;
+
+ // Sanitize min
+ if (min < 0)
+ min = 0;
+ else if (min > 100)
+ min = 100;
+
+ // Check relation between min and max
+ if (min > max)
+ max = max;
+
+ SpanQueryWrapper sqw = this.fromJson(operands.get(0));
+
+ if (sqw.maybeExtension())
+ return sqw.setMin(min).setMax(max);
+
+ return new SpanRepetitionQueryWrapper(sqw, min, max);
+ };
+
+
+ // Deserialize operation:submatch
+ @Deprecated
+ private SpanQueryWrapper _operationSubmatchFromJson (JsonNode json, JsonNode operands)
+ throws QueryException {
+
+ int number = 1;
+
+ this.addMessage(0, "operation:submatch is deprecated");
+
+ if (operands.size() != 1)
+ throw new QueryException(705, "Number of operands is not acceptable");
+
+ if (json.has("classRef")) {
+ if (json.has("classRefOp")) {
+ throw new QueryException(
+ 761,
+ "Class reference operators are currently not supported"
+ );
+ };
+
+ number = json.get("classRef").get(0).asInt();
+ }
+ else if (json.has("spanRef")) {
+ throw new QueryException(
+ 762,
+ "Span references are currently not supported"
+ );
+ };
+
+ return new SpanMatchModifyQueryWrapper(
+ this.fromJson(operands.get(0)), number
+ );
+ };
+
+
+ // Deserialize operation:class
+ private SpanQueryWrapper _operationClassFromJson (JsonNode json, JsonNode operands)
+ throws QueryException {
+ int number = 1;
+
+ // Too many operands
+ if (operands.size() != 1)
+ throw new QueryException(705, "Number of operands is not acceptable");
+
+ // Get class number
+ if (json.has("classOut")) {
+ number = json.get("classOut").asInt(0);
+ }
+ // <legacyCode>
+ else if (json.has("class")) {
+ number = json.get("class").asInt(0);
+ };
+ // </legacyCode>
+
+ // Class reference check
+ if (json.has("classRefCheck")) {
+ this.addWarning(
+ 764,
+ "Class reference checks are currently " +
+ "not supported - results may not be correct"
+ );
+ };
+
+ // Class reference operation
+ // This has to be done after class ref check
+ if (json.has("classRefOp")) {
+ throw new QueryException(
+ 761,
+ "Class reference operators are currently not supported"
+ );
+ };
+
+ // Number is set
+ if (number > 0) {
+ if (operands.size() != 1) {
+ throw new QueryException(
+ 705,
+ "Number of operands is not acceptable"
+ );
+ };
+
+ if (DEBUG) log.trace("Found Class definition for {}", number);
+
+ if (number > MAX_CLASS_NUM) {
+ throw new QueryException(
+ 709,
+ "Valid class numbers exceeded"
+ );
+ };
+
+ // Serialize operand
+ SpanQueryWrapper sqw = this.fromJson(operands.get(0));
+
+ // Problematic
+ if (sqw.maybeExtension())
+ return sqw.setClassNumber(number);
+
+ return new SpanClassQueryWrapper(sqw, number);
+ };
+
+ throw new QueryException(710, "Class attribute missing");
+ };
+
+
+ // Deserialize operation:sequence
+ private SpanQueryWrapper _operationSequenceFromJson (JsonNode json, JsonNode operands)
+ throws QueryException {
+ // Sequence with only one operand
+ if (operands.size() == 1)
+ return this.fromJson(operands.get(0));
+
+ SpanSequenceQueryWrapper sseqqw = this.seq();
+
+ // Say if the operand order is important
+ if (json.has("inOrder"))
+ sseqqw.setInOrder(json.get("inOrder").asBoolean());
+
+ // Introduce distance constraints
+ // ATTENTION: Distances have to be set before segments are added
+ if (json.has("distances")) {
+
+ // THIS IS NO LONGER NECESSARY, AS IT IS COVERED BY FRAMES
+ if (json.has("exclude") && json.get("exclude").asBoolean()) {
+ throw new QueryException(
+ 763,
+ "Excluding distance constraints are currently not supported"
+ );
+ };
+
+ if (!json.get("distances").isArray()) {
+ throw new QueryException(
+ 707,
+ "Distance Constraints have to be defined as arrays"
+ );
+ };
+
+ // TEMPORARY: Workaround for group distances
+ JsonNode firstDistance = json.get("distances").get(0);
+
+ if (!firstDistance.has("@type")) {
+ throw new QueryException(
+ 701,
+ "JSON-LD group has no @type attribute"
+ );
+ };
+
+ JsonNode distances;
+ if (firstDistance.get("@type").asText().equals("korap:group")) {
+ if (!firstDistance.has("operands") ||
+ !firstDistance.get("operands").isArray())
+ throw new QueryException(704, "Operation needs operand list");
+
+ distances = firstDistance.get("operands");
+ }
+
+ // Support korap distances
+ // Support cosmas distances
+ else if (firstDistance.get("@type").asText().equals("korap:distance")
+ ||
+ firstDistance.get("@type").asText().equals("cosmas:distance")) {
+ distances = json.get("distances");
+ }
+
+ else
+ throw new QueryException(708, "No valid distances defined");
+
+ // Add all distance constraint to query
+ for (JsonNode constraint : distances) {
+ String unit = "w";
+ if (constraint.has("key"))
+ unit = constraint.get("key").asText();
+
+ // There is a maximum of 100 fix
+ int min = 0, max = 100;
+ if (constraint.has("boundary")) {
+ Boundary b = new Boundary(constraint.get("boundary"), 0,100);
+ min = b.min;
+ max = b.max;
+ }
+ else {
+ if (constraint.has("min"))
+ min = constraint.get("min").asInt(0);
+ if (constraint.has("max"))
+ max = constraint.get("max").asInt(100);
+ };
+
+ // Add foundry and layer to the unit for new indices
+ if (constraint.has("foundry") &&
+ constraint.has("layer") &&
+ constraint.get("foundry").asText().length() > 0 &&
+ constraint.get("layer").asText().length() > 0) {
+
+ StringBuilder value = new StringBuilder();
+ value.append(constraint.get("foundry").asText());
+ value.append('/');
+ value.append(constraint.get("layer").asText());
+ value.append(':').append(unit);
+ unit = value.toString();
+ };
+
+ // Sanitize boundary
+ if (max < min) max = min;
+
+ if (DEBUG)
+ log.trace("Add distance constraint of '{}': {}-{}",
+ unit, min, max);
+
+ sseqqw.withConstraint(min, max, unit);
+ };
+ };
+
+ // Add segments to sequence
+ for (JsonNode operand : operands) {
+ sseqqw.append(this.fromJson(operand));
+ };
+
+ // inOrder was set to false without a distance constraint
+ if (!sseqqw.isInOrder() && !sseqqw.hasConstraints()) {
+ sseqqw.withConstraint(1,1,"w");
+ };
+
+ return sseqqw;
+ };
+
+
+ // Segment
private SpanQueryWrapper _segFromJson (JsonNode json) throws QueryException {
+ if (!json.has("@type"))
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
- if (!json.has("@type"))
- throw new QueryException(701, "JSON-LD group has no @type attribute");
+ String type = json.get("@type").asText();
- String type = json.get("@type").asText();
+ if (DEBUG)
+ log.trace("Wrap new token definition by {}", type);
- if (DEBUG)
- log.trace("Wrap new token definition by {}", type);
+ switch (type) {
+ case "korap:term":
+ String match = "match:eq";
+ if (json.has("match"))
+ match = json.get("match").asText();
+
+ switch (match) {
+ case "match:ne":
+ if (DEBUG)
+ log.trace("Term is negated");
+ SpanSegmentQueryWrapper ssqw =
+ (SpanSegmentQueryWrapper) this._termFromJson(json);
+ ssqw.makeNegative();
+ return this.seg().without(ssqw);
+ case "match:eq":
+ return this._termFromJson(json);
+ };
- switch (type) {
+ throw new QueryException(741, "Match relation unknown");
- case "korap:term":
- String match = "match:eq";
- if (json.has("match"))
- match = json.get("match").asText();
+ case "korap:termGroup":
- switch (match) {
- case "match:ne":
- if (DEBUG)
- log.trace("Term is negated");
- SpanSegmentQueryWrapper ssqw =
- (SpanSegmentQueryWrapper) this._termFromJson(json);
- ssqw.makeNegative();
- return this.seg().without(ssqw);
- case "match:eq":
- return this._termFromJson(json);
- };
+ if (!json.has("operands"))
+ throw new QueryException(742, "Term group needs operand list");
- throw new QueryException(741, "Match relation unknown");
+ // Get operands
+ JsonNode operands = json.get("operands");
- case "korap:termGroup":
+ SpanSegmentQueryWrapper ssegqw = this.seg();
+
+ if (!json.has("relation"))
+ throw new QueryException(743, "Term group expects a relation");
- if (!json.has("operands"))
- throw new QueryException(742, "Term group needs operand list");
+ switch (json.get("relation").asText()) {
+ case "relation:and":
- // Get operands
- JsonNode operands = json.get("operands");
-
- SpanSegmentQueryWrapper ssegqw = this.seg();
-
- if (!json.has("relation"))
- throw new QueryException(743, "Term group expects a relation");
-
- switch (json.get("relation").asText()) {
- case "relation:and":
-
- for (JsonNode operand : operands) {
- SpanQueryWrapper part = this._segFromJson(operand);
- if (part instanceof SpanAlterQueryWrapper) {
- ssegqw.with((SpanAlterQueryWrapper) part);
- }
- else if (part instanceof SpanRegexQueryWrapper) {
- ssegqw.with((SpanRegexQueryWrapper) part);
- }
- else if (part instanceof SpanSegmentQueryWrapper) {
- ssegqw.with((SpanSegmentQueryWrapper) part);
- }
- else {
- throw new QueryException(
- 744, "Operand not supported in term group"
+ for (JsonNode operand : operands) {
+ SpanQueryWrapper part = this._segFromJson(operand);
+ if (part instanceof SpanAlterQueryWrapper) {
+ ssegqw.with((SpanAlterQueryWrapper) part);
+ }
+ else if (part instanceof SpanRegexQueryWrapper) {
+ ssegqw.with((SpanRegexQueryWrapper) part);
+ }
+ else if (part instanceof SpanSegmentQueryWrapper) {
+ ssegqw.with((SpanSegmentQueryWrapper) part);
+ }
+ else {
+ throw new QueryException(
+ 744,
+ "Operand not supported in term group"
);
- };
- };
- return ssegqw;
+ };
+ };
+ return ssegqw;
- case "relation:or":
+ case "relation:or":
- SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
- for (JsonNode operand : operands) {
- ssaq.or(this._segFromJson(operand));
- };
- return ssaq;
- };
- };
- throw new QueryException(745, "Token type is not supported");
+ SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
+ for (JsonNode operand : operands) {
+ ssaq.or(this._segFromJson(operand));
+ };
+ return ssaq;
+ };
+ };
+ throw new QueryException(745, "Token type is not supported");
};
private SpanQueryWrapper _termFromJson (JsonNode json) throws QueryException {
- if (!json.has("key") || json.get("key").asText().length() < 1)
- throw new QueryException(740, "Key definition is missing in term or span");
+
+ if (!json.has("key") || json.get("key").asText().length() < 1)
+ throw new QueryException(740, "Key definition is missing in term or span");
- if (!json.has("@type"))
- throw new QueryException(701, "JSON-LD group has no @type attribute");
+ if (!json.has("@type"))
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
- Boolean isTerm = json.get("@type").asText().equals("korap:term") ? true : false;
- Boolean isCaseInsensitive = false;
+ Boolean isTerm = json.get("@type").asText().equals("korap:term") ? true : false;
+ Boolean isCaseInsensitive = false;
- if (json.has("caseInsensitive") && json.get("caseInsensitive").asBoolean())
- isCaseInsensitive = true;
+ if (json.has("caseInsensitive") && json.get("caseInsensitive").asBoolean())
+ isCaseInsensitive = true;
- StringBuilder value = new StringBuilder();
+ StringBuilder value = new StringBuilder();
+
+ // expect orth? expect lemma?
+ // s:den | i:den | cnx/l:die | mate/m:mood:ind | cnx/syn:@PREMOD |
+ // mate/m:number:sg | opennlp/p:ART
- // expect orth? expect lemma?
- // s:den | i:den | cnx/l:die | mate/m:mood:ind | cnx/syn:@PREMOD |
- // mate/m:number:sg | opennlp/p:ART
+ if (json.has("foundry") && json.get("foundry").asText().length() > 0)
+ value.append(json.get("foundry").asText()).append('/');
- if (json.has("foundry") && json.get("foundry").asText().length() > 0)
- value.append(json.get("foundry").asText()).append('/');
+ // No default foundry defined
+ if (json.has("layer") && json.get("layer").asText().length() > 0) {
+ String layer = json.get("layer").asText();
+ switch (layer) {
- // No default foundry defined
+ case "lemma":
+ layer = "l";
+ break;
- if (json.has("layer") && json.get("layer").asText().length() > 0) {
- String layer = json.get("layer").asText();
- switch (layer) {
+ case "pos":
+ layer = "p";
+ break;
- case "lemma":
- layer = "l";
- break;
+ case "orth":
+ // TODO: THIS IS A BUG! AND SHOULD BE NAMED "SURFACE" or .
+ layer = "s";
+ break;
- case "pos":
- layer = "p";
- break;
+ case "struct":
+ layer = "s";
+ break;
- case "orth":
- // TODO: THIS IS A BUG! AND SHOULD BE NAMED "SURFACE"
- layer = "s";
- break;
+ case "const":
+ layer = "c";
+ break;
+ };
- case "struct":
- layer = "s";
- break;
+ if (isCaseInsensitive && isTerm) {
+ if (layer.equals("s")) {
+ layer = "i";
+ }
+ else {
+ this.addWarning(
+ 767,
+ "Case insensitivity is currently not supported for this layer"
+ );
+ };
+ };
- case "const":
- layer = "c";
- break;
- };
+ // Ignore foundry for orth layer
+ if (layer.equals("s") || layer.equals("i"))
+ value.setLength(0);
- if (isCaseInsensitive && isTerm) {
- if (layer.equals("s")) {
- layer = "i";
- }
- else {
- this.addWarning(
- 767,
- "Case insensitivity is currently not supported for this layer"
- );
- };
- };
+ value.append(layer).append(':');
+ };
- // Ignore foundry for orth layer
- if (layer.equals("s") || layer.equals("i"))
- value.setLength(0);
+ if (json.has("key") && json.get("key").asText().length() > 0) {
+ String key = json.get("key").asText();
+ value.append(isCaseInsensitive ? key.toLowerCase() : key);
+ };
- value.append(layer).append(':');
- };
+ if (json.has("value") && json.get("value").asText().length() > 0)
+ value.append(':').append(json.get("value").asText());
- if (json.has("key") && json.get("key").asText().length() > 0) {
- String key = json.get("key").asText();
- value.append(isCaseInsensitive ? key.toLowerCase() : key);
- };
+ // Regular expression or wildcard
+ if (isTerm && json.has("type")) {
+ switch (json.get("type").asText()) {
+ case "type:regex":
+ return this.seg(this.re(value.toString(), isCaseInsensitive));
+ case "type:wildcard":
+ return this.seq(this.wc(value.toString(), isCaseInsensitive));
+ case "type:string":
+ break;
+ default:
+ this.addWarning(746, "Term type is not supported - treated as a string");
+ };
+ };
- if (json.has("value") && json.get("value").asText().length() > 0)
- value.append(':').append(json.get("value").asText());
+ if (isTerm)
+ return this.seg(value.toString());
- // Regular expression or wildcard
- if (isTerm && json.has("type")) {
- switch (json.get("type").asText()) {
- case "type:regex":
- return this.seg(this.re(value.toString(), isCaseInsensitive));
- case "type:wildcard":
- return this.seq(this.wc(value.toString(), isCaseInsensitive));
- case "type:string":
- break;
- default:
- this.addWarning(746, "Term type is not supported - treated as a string");
- };
- };
+ // Attributes currently not supported
+ if (json.has("attr"))
+ this.addWarning(
+ 768,
+ "Attributes are currently not supported - results may not be correct"
+ );
- if (isTerm)
- return this.seg(value.toString());
-
- if (json.has("attr"))
- this.addWarning(
- 768,
- "Attributes are currently not supported - results may not be correct");
-
- return this.tag(value.toString());
+ return this.tag(value.toString());
};
- /*
- public boolean hasWarning () {
- if (this.warning != null)
- return true;
- return true;
- };
- public String getWarning () {
- return this.warning;
- };
-
- public void addWarning (String msg) {
- if (msg == null)
- return;
- if (this.warning == null)
- this.warning = msg;
- else
- this.warning += "; " + msg;
- };
-
- public void setWarning (String warning) {
- this.warning = warning;
- };
- */
-
- // SpanRegexQueryWrapper
/**
* Create a query object based on a regular expression.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanRegexQueryWrapper re = kq.re(".+?");
+ * </pre></blockquote>
+ *
* @param re The regular expession as a string.
+ * @return A {@link SpanRegexQueryWrapper} object.
*/
public SpanRegexQueryWrapper re (String re) {
- return new SpanRegexQueryWrapper(this.field, re, RegExp.ALL, false);
+ return new SpanRegexQueryWrapper(this.field, re, RegExp.ALL, false);
};
+
/**
* Create a query object based on a regular expression.
+ *
+ * Supports flags as defined in {@link org.apache.lucene.util.automaton.RegExp}:
+ * <ul>
+ * <li><tt>RegExp.ALL</tt> - enables all optional regexp syntax</li>
+ * <li><tt>RegExp.ANYSTRING</tt> - enables anystring (@)</li>
+ * <li><tt>RegExp.AUTOMATON</tt> - enables named automata (<identifier>)</li>
+ * <li><tt>RegExp.COMPLEMENT</tt> - enables complement (~)</li>
+ * <li><tt>RegExp.EMPTY</tt> - enables empty language (#)</li>
+ * <li><tt>RegExp.INTERSECTION</tt> - enables intersection (&)</li>
+ * <li><tt>RegExp.INTERVAL</tt> - enables numerical intervals (<n-m>)</li>
+ * <li><tt>RegExp.NONE</tt> - enables no optional regexp syntax</li>
+ * </ul>
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanRegexQueryWrapper re = kq.re("[Aa]lternatives?", RegExp.NONE);
+ * </pre></blockquote>
+ *
* @param re The regular expession as a string.
- * @param flas The regular expession flag as an integer.
+ * @param flags The flag for the regular expression.
+ * @return A {@link SpanRegexQueryWrapper} object.
*/
public SpanRegexQueryWrapper re (String re, int flags) {
- return new SpanRegexQueryWrapper(this.field, re, flags, false);
+ return new SpanRegexQueryWrapper(this.field, re, flags, false);
};
+
/**
* Create a query object based on a regular expression.
+ *
+ * Supports flags (see above) and case insensitivity.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanRegexQueryWrapper re = kq.re("alternatives?", RegExp.NONE, true);
+ * </pre></blockquote>
+ *
* @param re The regular expession as a string.
- * @param flag The regular expession flag.
+ * @param flags The flag for the regular expression.
* @param caseinsensitive A boolean value indicating case insensitivity.
+ * @return A {@link SpanRegexQueryWrapper} object.
*/
public SpanRegexQueryWrapper re (String re, int flags, boolean caseinsensitive) {
- return new SpanRegexQueryWrapper(this.field, re, flags, caseinsensitive);
+ return new SpanRegexQueryWrapper(this.field, re, flags, caseinsensitive);
};
+
/**
* Create a query object based on a regular expression.
+ *
+ * Supports case insensitivity.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanRegexQueryWrapper re = kq.re("alternatives?", true);
+ * </pre></blockquote>
+ *
* @param re The regular expession as a string.
- * @param caseinsensitive A boolean value indicating case insensitivity.
+ * @param flags The flag for the regular expression.
+ * @return A {@link SpanRegexQueryWrapper} object.
*/
public SpanRegexQueryWrapper re (String re, boolean caseinsensitive) {
- return new SpanRegexQueryWrapper(this.field, re, RegExp.ALL, caseinsensitive);
+ return new SpanRegexQueryWrapper(this.field, re, RegExp.ALL, caseinsensitive);
};
- // SpanWildcardQueryWrapper
/**
* Create a query object based on a wildcard term.
+ * <tt>*</tt> indicates an optional sequence of arbitrary characters,
+ * <tt>?</tt> indicates a single character,
+ * <tt>\</tt> can be used for escaping.
+ *
* @param wc The wildcard term as a string.
+ * @return A {@link SpanWildcardQueryWrapper} object.
*/
public SpanWildcardQueryWrapper wc (String wc) {
- return new SpanWildcardQueryWrapper(this.field, wc, false);
+ return new SpanWildcardQueryWrapper(this.field, wc, false);
};
/**
* Create a query object based on a wildcard term.
+ * <tt>*</tt> indicates an optional sequence of arbitrary characters,
+ * <tt>?</tt> indicates a single character,
+ * <tt>\</tt> can be used for escaping.
+ *
+ * Supports case insensitivity.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanWildcardQueryWrapper wc = kq.wc("wall*", true);
+ * </pre></blockquote>
+ *
* @param wc The wildcard term as a string.
* @param caseinsensitive A boolean value indicating case insensitivity.
+ * @return A {@link SpanWildcardQueryWrapper} object.
*/
public SpanWildcardQueryWrapper wc (String wc, boolean caseinsensitive) {
- return new SpanWildcardQueryWrapper(this.field, wc, caseinsensitive);
+ return new SpanWildcardQueryWrapper(this.field, wc, caseinsensitive);
};
- // SpanSegmentQueries
/**
* Create a segment query object.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanSegmentQueryWrapper seg = kq.seg();
+ * </pre></blockquote>
+ *
+ * @return A {@link SpanSegmentQueryWrapper} object.
*/
public SpanSegmentQueryWrapper seg () {
- return new SpanSegmentQueryWrapper(this.field);
+ return new SpanSegmentQueryWrapper(this.field);
};
/**
* Create a segment query object.
+ * Supports sequences of strings or {@link SpanRegexQueryWrapper},
+ * and {@link SpanAlterQueryWrapper} objects.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanSegmentQueryWrapper seg = kq.seg(
+ * kq.re("mate/p=.*?"),
+ * kq.re("opennlp/p=.*?")
+ * );
+ * </pre></blockquote>
+ *
* @param terms[] An array of terms, the segment consists of.
+ * @return A {@link SpanSegmentQueryWrapper} object.
*/
+ // Sequence of regular expression queries
public SpanSegmentQueryWrapper seg (SpanRegexQueryWrapper ... terms) {
- SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
- for (SpanRegexQueryWrapper t : terms) {
- ssq.with(t);
- };
- return ssq;
+ SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
+ for (SpanRegexQueryWrapper t : terms)
+ ssq.with(t);
+ return ssq;
};
+ // Sequence of alternative queries
public SpanSegmentQueryWrapper seg (SpanAlterQueryWrapper ... terms) {
- SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
- for (SpanAlterQueryWrapper t : terms) {
- ssq.with(t);
- };
- return ssq;
+ SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
+ for (SpanAlterQueryWrapper t : terms)
+ ssq.with(t);
+ return ssq;
};
+ // Sequence of alternative queries
public SpanSegmentQueryWrapper seg (String ... terms) {
- SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
- for (String t : terms) {
- ssq.with(t);
- };
- return ssq;
+ SpanSegmentQueryWrapper ssq = new SpanSegmentQueryWrapper(this.field);
+ for (String t : terms)
+ ssq.with(t);
+ return ssq;
};
- // Create an empty segment
+ /**
+ * Create an empty query segment.
+ *
+ * <blockquote><pre>
+ * KorapQuery kq = new KorapQuery("tokens");
+ * SpanRepetitionQueryWrapper seg = kq.empty();
+ * </pre></blockquote>
+ */
public SpanRepetitionQueryWrapper empty () {
- return new SpanRepetitionQueryWrapper();
+ return new SpanRepetitionQueryWrapper();
};
- // SpanSegmentAlterQueries
+
+ // TODO: Further JavaDocs
+
+
/**
* Create a segment alternation query object.
* @param terms[] An array of alternative terms.
*/
public SpanAlterQueryWrapper or (SpanQueryWrapper ... terms) {
- SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
- for (SpanQueryWrapper t : terms) {
- ssaq.or(t);
- };
- return ssaq;
+ SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
+ for (SpanQueryWrapper t : terms)
+ ssaq.or(t);
+ return ssaq;
};
+
public SpanAlterQueryWrapper or (String ... terms) {
- SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
- for (String t : terms) {
- ssaq.or(t);
- };
- return ssaq;
+ SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
+ for (String t : terms)
+ ssaq.or(t);
+ return ssaq;
};
@@ -892,7 +1106,7 @@
* Create a sequence of segments query object.
*/
public SpanSequenceQueryWrapper seq () {
- return new SpanSequenceQueryWrapper(this.field);
+ return new SpanSequenceQueryWrapper(this.field);
};
@@ -901,11 +1115,10 @@
* @param terms[] An array of segment defining terms.
*/
public SpanSequenceQueryWrapper seq (SpanQueryWrapper ... terms) {
- SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper(this.field);
- for (SpanQueryWrapper t : terms) {
- sssq.append(t);
- };
- return sssq;
+ SpanSequenceQueryWrapper sssq = new SpanSequenceQueryWrapper(this.field);
+ for (SpanQueryWrapper t : terms)
+ sssq.append(t);
+ return sssq;
};
@@ -914,29 +1127,30 @@
* @param re A SpanSegmentRegexQuery, starting the sequence.
*/
public SpanSequenceQueryWrapper seq (SpanRegexQueryWrapper re) {
- return new SpanSequenceQueryWrapper(this.field, re);
+ return new SpanSequenceQueryWrapper(this.field, re);
};
public SpanSequenceQueryWrapper seq (Object ... terms) {
- SpanSequenceQueryWrapper ssq = new SpanSequenceQueryWrapper(this.field);
- for (Object t : terms) {
- if (t instanceof SpanQueryWrapper) {
- ssq.append((SpanQueryWrapper) t);
- }
- else if (t instanceof SpanRegexQueryWrapper) {
- ssq.append((SpanRegexQueryWrapper) t);
- }
- else {
- log.error("{} is not an acceptable parameter for seq()", t.getClass());
- return ssq;
- };
- };
- return ssq;
+ SpanSequenceQueryWrapper ssq = new SpanSequenceQueryWrapper(this.field);
+ for (Object t : terms) {
+ if (t instanceof SpanQueryWrapper) {
+ ssq.append((SpanQueryWrapper) t);
+ }
+ else if (t instanceof SpanRegexQueryWrapper) {
+ ssq.append((SpanRegexQueryWrapper) t);
+ }
+ else {
+ log.error("{} is not an acceptable parameter for seq()", t.getClass());
+ return ssq;
+ };
+ };
+ return ssq;
};
+
public SpanElementQueryWrapper tag (String element) {
- return new SpanElementQueryWrapper(this.field, element);
+ return new SpanElementQueryWrapper(this.field, element);
};
/**
@@ -946,75 +1160,75 @@
*/
@Deprecated
public SpanWithinQueryWrapper within (SpanQueryWrapper element,
- SpanQueryWrapper embedded) {
- return new SpanWithinQueryWrapper(element, embedded);
+ SpanQueryWrapper embedded) {
+ return new SpanWithinQueryWrapper(element, embedded);
};
-
+
public SpanWithinQueryWrapper contains (SpanQueryWrapper element,
- SpanQueryWrapper embedded) {
- return new SpanWithinQueryWrapper(element, embedded, WITHIN);
+ SpanQueryWrapper embedded) {
+ return new SpanWithinQueryWrapper(element, embedded, WITHIN);
};
public SpanWithinQueryWrapper startswith (SpanQueryWrapper element,
- SpanQueryWrapper embedded) {
- return new SpanWithinQueryWrapper(element, embedded, STARTSWITH);
+ SpanQueryWrapper embedded) {
+ return new SpanWithinQueryWrapper(element, embedded, STARTSWITH);
};
public SpanWithinQueryWrapper endswith (SpanQueryWrapper element,
- SpanQueryWrapper embedded) {
- return new SpanWithinQueryWrapper(element, embedded, ENDSWITH);
+ SpanQueryWrapper embedded) {
+ return new SpanWithinQueryWrapper(element, embedded, ENDSWITH);
};
public SpanWithinQueryWrapper overlaps (SpanQueryWrapper element,
- SpanQueryWrapper embedded) {
- return new SpanWithinQueryWrapper(element, embedded, OVERLAP);
+ SpanQueryWrapper embedded) {
+ return new SpanWithinQueryWrapper(element, embedded, OVERLAP);
};
public SpanWithinQueryWrapper matches (SpanQueryWrapper element,
- SpanQueryWrapper embedded) {
- return new SpanWithinQueryWrapper(element, embedded, MATCH);
+ SpanQueryWrapper embedded) {
+ return new SpanWithinQueryWrapper(element, embedded, MATCH);
};
// Class
public SpanClassQueryWrapper _ (byte number, SpanQueryWrapper element) {
- return new SpanClassQueryWrapper(element, number);
+ return new SpanClassQueryWrapper(element, number);
};
public SpanClassQueryWrapper _ (int number, SpanQueryWrapper element) {
- return new SpanClassQueryWrapper(element, number);
+ return new SpanClassQueryWrapper(element, number);
};
public SpanClassQueryWrapper _ (short number, SpanQueryWrapper element) {
- return new SpanClassQueryWrapper(element, number);
+ return new SpanClassQueryWrapper(element, number);
};
public SpanClassQueryWrapper _ (SpanQueryWrapper element) {
- return new SpanClassQueryWrapper(element);
+ return new SpanClassQueryWrapper(element);
};
// MatchModify
public SpanMatchModifyQueryWrapper shrink (byte number, SpanQueryWrapper element) {
- return new SpanMatchModifyQueryWrapper(element, number);
+ return new SpanMatchModifyQueryWrapper(element, number);
};
public SpanMatchModifyQueryWrapper shrink (int number, SpanQueryWrapper element) {
- return new SpanMatchModifyQueryWrapper(element, number);
+ return new SpanMatchModifyQueryWrapper(element, number);
};
public SpanMatchModifyQueryWrapper shrink (short number, SpanQueryWrapper element) {
- return new SpanMatchModifyQueryWrapper(element, number);
+ return new SpanMatchModifyQueryWrapper(element, number);
};
public SpanMatchModifyQueryWrapper shrink (SpanQueryWrapper element) {
- return new SpanMatchModifyQueryWrapper(element);
+ return new SpanMatchModifyQueryWrapper(element);
};
// Repetition
public SpanRepetitionQueryWrapper repeat (SpanQueryWrapper element, int exact) {
- return new SpanRepetitionQueryWrapper(element, exact);
+ return new SpanRepetitionQueryWrapper(element, exact);
};
public SpanRepetitionQueryWrapper repeat (SpanQueryWrapper element, int min, int max) {
- return new SpanRepetitionQueryWrapper(element, min, max);
+ return new SpanRepetitionQueryWrapper(element, min, max);
};
};
diff --git a/src/main/java/de/ids_mannheim/korap/KorapResult.java b/src/main/java/de/ids_mannheim/korap/KorapResult.java
index 524f54f..87755cf 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapResult.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapResult.java
@@ -24,6 +24,8 @@
/**
* Response class for search results.
*
+ * TODO: Synopsis
+ *
* @author diewald
* @see KorapResponse
*/
@@ -43,8 +45,9 @@
private SearchContext context;
- private short itemsPerPage = ITEMS_PER_PAGE,
- itemsPerResource = 0;
+ private short
+ itemsPerPage = ITEMS_PER_PAGE,
+ itemsPerResource = 0;
private JsonNode request;
@@ -99,7 +102,7 @@
/**
- * Get number of items shown per page.
+ * Get the number of items (documents) shown per page.
*
* @return Number of items shown per page.
*/
@@ -109,7 +112,7 @@
/**
- * Set number of items shown per page.
+ * Set the number of items (documents) shown per page.
*
* @param count Number of items shown per page.
* @return {@link KorapResult} object for chaining.
@@ -142,106 +145,168 @@
};
- @JsonIgnore
- public void setItemsPerResource (short value) {
- this.itemsPerResource = value;
- };
-
- @JsonIgnore
- public void setItemsPerResource (int value) {
- this.itemsPerResource = (short) value;
- };
-
- @JsonIgnore
+ /**
+ * Get the number of items shown per resource (document).
+ * Defaults to <tt>0</tt>, which is infinite.
+ *
+ * @return The number of items shown per resource.
+ */
public short getItemsPerResource () {
- return this.itemsPerResource;
+ return this.itemsPerResource;
};
+
+ /**
+ * Set the number of items (matches) shown per resource (text).
+ * Defaults to <tt>0</tt>, which is infinite.
+ *
+ * @param value The number of items shown per resource.
+ * @return {@link KorapResult} object for chaining.
+ */
+ public KorapResult setItemsPerResource (short value) {
+ this.itemsPerResource = value;
+ return this;
+ };
+
+
+ /**
+ * Set the number of items (matches) shown per resource (document).
+ * Defaults to <tt>0</tt>, which is infinite.
+ *
+ * @param value The number of items shown per resource.
+ * @return {@link KorapResult} object for chaining.
+ */
+ public KorapResult setItemsPerResource (int value) {
+ this.itemsPerResource = (short) value;
+ return this;
+ };
+
+
+ /**
+ * Get the string representation of the search query.
+ *
+ * @return The string representation of the search query.
+ */
public String getQuery () {
return this.query;
};
+
+ /**
+ * Get a certain {@link KorapMatch} by index.
+ *
+ * @param index The numerical index of the match,
+ * starts with <tt>0</tt>.
+ * @return The {@link KorapMatch} object.
+ */
@JsonIgnore
public KorapMatch getMatch (int index) {
return this.matches.get(index);
};
- @JsonIgnore
+
+ /**
+ * Get the list of {@link KorapMatch} matches.
+ *
+ * @return The list of {@link KorapMatch} objects.
+ */
public List<KorapMatch> getMatches() {
return this.matches;
};
+
+ /**
+ * Get the number of the first match in the result set
+ * (<i>aka</i> the offset). Starts with <tt>0</tt>.
+ *
+ * @return The index number of the first match in the result set.
+ */
public int getStartIndex () {
return startIndex;
};
- @JsonIgnore
- public KorapResult setContext(SearchContext context) {
+
+ /**
+ * Get the context parameters of the search by means of a
+ * {@link SearchContext} object.
+ *
+ * @return The {@link SearchContext} object.
+ */
+ public SearchContext getContext () {
+ return this.context;
+ };
+
+
+ /**
+ * Set the context parameters of the search by means of a
+ * {@link SearchContext} object.
+ *
+ * @param context The {@link SearchContext} object providing
+ * search context parameters.
+ * @return {@link KorapResult} object for chaining.
+ */
+ public KorapResult setContext (SearchContext context) {
this.context = context;
return this;
- }
+ };
- @JsonIgnore
- public SearchContext getContext() {
- return this.context;
- }
-
-
+ /**
+ * Serialize the result set as a {@link JsonNode}.
+ *
+ * @return {@link JsonNode} representation of the search results.
+ */
public JsonNode toJsonNode () {
- ObjectNode json = (ObjectNode) mapper.valueToTree(super.toJsonNode());
+ ObjectNode json = (ObjectNode) mapper.valueToTree(super.toJsonNode());
- if (this.context != null)
- json.put("context", this.getContext().toJsonNode());
+ // Relevant context setting
+ if (this.context != null)
+ json.put("context", this.getContext().toJsonNode());
- if (this.itemsPerResource > 0)
- json.put("itemsPerResource",
- this.itemsPerResource);
- json.put("itemsPerPage",
- this.itemsPerPage);
+ // ItemsPerPage
+ json.put("itemsPerPage", this.itemsPerPage);
- // TODO: If test
- if (this.request != null)
- json.put("request", this.request);
+ // Relevant itemsPerResource setting
+ if (this.itemsPerResource > 0)
+ json.put("itemsPerResource", this.itemsPerResource);
- // TODO: If test
- if (this.request != null)
- json.put("request", this.request);
- if (this.query != null)
- json.put("query", this.query);
+ json.put("startIndex", this.startIndex);
- json.put("startIndex", this.startIndex);
+ // Add matches
+ if (this.matches != null)
+ json.putPOJO("matches", this.getMatches());
- json.put("totalResults", this.getTotalResults());
- // Add matches
- if (this.matches != null)
- json.putPOJO("matches", this.getMatches());
+ // TODO: <test>
+ if (this.request != null)
+ json.put("request", this.request);
+ if (this.query != null)
+ json.put("query", this.query);
+ // </test>
- return json;
+ return json;
};
// For Collocation Analysis API
+ @Deprecated
public String toTokenListJsonString () {
ObjectNode json = (ObjectNode) mapper.valueToTree(this);
-
- ArrayNode array = json.putArray("matches");
+
+ ArrayNode array = json.putArray("matches");
- // Add matches as token lists
- for (KorapMatch km : this.getMatches()) {
- array.add(km.toTokenList());
- };
+ // Add matches as token lists
+ for (KorapMatch km : this.getMatches())
+ array.add(km.toTokenList());
try {
return mapper.writeValueAsString(json);
}
- catch (Exception e) {
+ catch (Exception e) {
log.warn(e.getLocalizedMessage());
};
-
+
return "{}";
};
-
};
diff --git a/src/main/java/de/ids_mannheim/korap/KorapSearch.java b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
index 08c2da1..88100df 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapSearch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
@@ -193,214 +193,200 @@
for (JsonNode field : (JsonNode) meta.get("fields")) {
this.addField(field.asText());
};
- }
- else
- this.addField(meta.get("fields").asText());
- };
- };
- };
- }
+ }
+ else
+ this.addField(meta.get("fields").asText());
+ };
+ };
+ };
+ }
- // Unable to parse JSON
- catch (IOException e) {
- this.addError(621, "Unable to parse JSON");
- };
+ // Unable to parse JSON
+ catch (IOException e) {
+ this.addError(621, "Unable to parse JSON");
+ };
};
// Maybe accept queryWrapperStuff
public KorapSearch (SpanQueryWrapper sqwi) {
- try {
- this.query = sqwi.toQuery();
- }
- catch (QueryException q) {
- this.addError(q.getErrorCode(), q.getMessage());
- };
+ try {
+ this.query = sqwi.toQuery();
+ }
+ catch (QueryException q) {
+ this.addError(q.getErrorCode(), q.getMessage());
+ };
};
-
+
public KorapSearch (SpanQuery sq) {
- this.query = sq;
+ this.query = sq;
};
// Empty constructor
public KorapSearch () { };
public long getTimeOut () {
- return this.timeout;
+ return this.timeout;
};
public void setTimeOut (long timeout) {
- this.timeout = timeout;
+ this.timeout = timeout;
};
public SpanQuery getQuery () {
- return this.query;
+ return this.query;
};
public JsonNode getRequest () {
- return this.request;
+ return this.request;
};
public KorapSearch setQuery (SpanQueryWrapper sqwi) {
- // this.copyNotifications(sqwi);
- try {
- this.query = sqwi.toQuery();
- }
- catch (QueryException q) {
- this.addError(q.getErrorCode(), q.getMessage());
- };
- return this;
+ // this.copyNotifications(sqwi);
+ try {
+ this.query = sqwi.toQuery();
+ }
+ catch (QueryException q) {
+ this.addError(q.getErrorCode(), q.getMessage());
+ };
+ return this;
};
public KorapSearch setQuery (SpanQuery sq) {
- this.query = sq;
- return this;
+ this.query = sq;
+ return this;
};
public SearchContext getContext () {
- return this.context;
+ return this.context;
};
public KorapSearch setContext (SearchContext context) {
- this.context = context;
- return this;
+ this.context = context;
+ return this;
};
public int getStartIndex () {
- return this.startIndex;
+ return this.startIndex;
};
-
+
public KorapSearch setStartIndex (int value) {
- if (value >= 0) {
- this.startIndex = value;
- }
- else {
- this.startIndex = 0;
- };
-
- return this;
+ this.startIndex = (value >= 0) ? value : 0;
+ return this;
};
public KorapSearch setStartPage (int value) {
- if (value >= 0) {
- this.setStartIndex((value * this.getCount()) - this.getCount());
- }
- else {
- this.startIndex = 0;
- };
-
- return this;
+ if (value >= 0)
+ this.setStartIndex((value * this.getCount()) - this.getCount());
+ else
+ this.startIndex = 0;
+ return this;
};
public short getCount () {
- return this.count;
+ return this.count;
};
public short getCountMax () {
- return this.countMax;
+ return this.countMax;
};
public int getLimit () {
- return this.limit;
+ return this.limit;
};
public KorapSearch setLimit (int limit) {
- if (limit > 0)
- this.limit = limit;
- return this;
+ if (limit > 0)
+ this.limit = limit;
+ return this;
};
public boolean doCutOff () {
- return this.cutOff;
+ return this.cutOff;
};
public KorapSearch setCutOff (boolean cutOff) {
- this.cutOff = cutOff;
- return this;
+ this.cutOff = cutOff;
+ return this;
};
public KorapSearch setCount (int value) {
- // Todo: Maybe update startIndex with known startPage!
- this.setCount((short) value);
- return this;
+ // Todo: Maybe update startIndex with known startPage!
+ this.setCount((short) value);
+ return this;
};
public KorapSearch setCount (short value) {
- if (value > 0) {
- if (value <= this.countMax)
- this.count = value;
- else
- this.count = this.countMax;
- };
- return this;
+ if (value > 0)
+ this.count = (value <= this.countMax) ? value : this.countMax;
+ return this;
};
public KorapSearch setItemsPerResource (short value) {
- if (value >= 0)
- this.itemsPerResource = value;
- return this;
+ if (value >= 0)
+ this.itemsPerResource = value;
+ return this;
};
public KorapSearch setItemsPerResource (int value) {
- return this.setItemsPerResource((short) value);
+ return this.setItemsPerResource((short) value);
};
public short getItemsPerResource () {
- return this.itemsPerResource;
+ return this.itemsPerResource;
};
// Add field to set of fields
public KorapSearch addField (String field) {
- this.fields.add(field);
- return this;
+ this.fields.add(field);
+ return this;
};
// Get set of fields
public HashSet<String> getFields () {
- return this.fields;
+ return this.fields;
};
public KorapSearch setCollection (KorapCollection kc) {
- this.collection = kc;
-
- // Copy messages from the collection
- this.copyNotificationsFrom(kc);
- kc.clearNotifications();
- return this;
+ this.collection = kc;
+
+ // Copy messages from the collection
+ this.copyNotificationsFrom(kc);
+ kc.clearNotifications();
+ return this;
};
public KorapCollection getCollection () {
- if (this.collection == null)
- this.collection = new KorapCollection();
-
- return this.collection;
+ if (this.collection == null)
+ this.collection = new KorapCollection();
+ return this.collection;
};
public KorapResult run (KorapIndex ki) {
- if (this.query == null) {
- KorapResult kr = new KorapResult();
- kr.setRequest(this.request);
+ if (this.query == null) {
+ KorapResult kr = new KorapResult();
+ kr.setRequest(this.request);
- if (this.hasErrors())
- kr.copyNotificationsFrom(this);
- else
- kr.addError(700, "No query given");
- return kr;
- };
+ if (this.hasErrors())
+ kr.copyNotificationsFrom(this);
+ else
+ kr.addError(700, "No query given");
+ return kr;
+ };
- if (this.hasErrors()) {
- KorapResult kr = new KorapResult();
+ if (this.hasErrors()) {
+ KorapResult kr = new KorapResult();
- // TODO: dev mode
- kr.setRequest(this.request);
- kr.copyNotificationsFrom(this);
- return kr;
- };
+ // TODO: dev mode
+ kr.setRequest(this.request);
+ kr.copyNotificationsFrom(this);
+ return kr;
+ };
- this.getCollection().setIndex(ki);
- KorapResult kr = ki.search(this);
- kr.setRequest(this.request);
- kr.copyNotificationsFrom(this);
- this.clearNotifications();
- return kr;
+ this.getCollection().setIndex(ki);
+ KorapResult kr = ki.search(this);
+ kr.setRequest(this.request);
+ kr.copyNotificationsFrom(this);
+ this.clearNotifications();
+ return kr;
};
};
diff --git a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWildcardQueryWrapper.java b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWildcardQueryWrapper.java
index 87d777a..4332856 100644
--- a/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWildcardQueryWrapper.java
+++ b/src/main/java/de/ids_mannheim/korap/query/wrap/SpanWildcardQueryWrapper.java
@@ -10,27 +10,27 @@
public class SpanWildcardQueryWrapper extends SpanQueryWrapper {
private SpanQuery query;
-
+
public SpanWildcardQueryWrapper (String field, String wc) {
- this(field, wc, false);
+ this(field, wc, false);
};
public SpanWildcardQueryWrapper (String field, String wc, boolean caseinsensitive) {
- if (caseinsensitive) {
- if (wc.startsWith("s:")) {
- wc = wc.replaceFirst("s:", "i:");
- };
- wc = wc.toLowerCase();
- };
- WildcardQuery wcquery = new WildcardQuery(new Term(field, wc));
- query = new SpanMultiTermQueryWrapper<WildcardQuery>( wcquery );
+ if (caseinsensitive) {
+ if (wc.startsWith("s:")) {
+ wc = wc.replaceFirst("s:", "i:");
+ };
+ wc = wc.toLowerCase();
+ };
+ WildcardQuery wcquery = new WildcardQuery(new Term(field, wc));
+ query = new SpanMultiTermQueryWrapper<WildcardQuery>( wcquery );
};
public SpanQuery toQuery() {
- return this.query;
+ return this.query;
};
public boolean isNull () {
- return false;
+ return false;
};
};
diff --git a/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java b/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
index 806d54c..97ca88c 100644
--- a/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
+++ b/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
@@ -32,8 +32,8 @@
private String version, name, node, listener;
private long
- totalTexts = -2, // Not set
- totalResults = -2; // Not set
+ totalResources = -2, // Not set
+ totalResults = -2; // Not set
private String benchmark;
private boolean timeExceeded = false;
@@ -266,47 +266,47 @@
/**
- * Get the total number of texts the total number of
+ * Get the total number of resources the total number of
* results occur in.
*
- * @return The total number of texts the total number of
+ * @return The total number of resources the total number of
* results occur in.
*/
- public long getTotalTexts () {
- if (this.totalTexts == -2)
+ public long getTotalResources () {
+ if (this.totalResources == -2)
return (long) 0;
- return this.totalTexts;
+ return this.totalResources;
};
/**
- * Set the total number of texts the total number of
+ * Set the total number of resources the total number of
* results occur in.
*
- * @param texts The total number of texts the total
+ * @param resources The total number of resources the total
* number of results occur in.
* @return {@link KorapResponse} object for chaining.
*/
- public KorapResponse setTotalTexts (long texts) {
- this.totalTexts = texts;
+ public KorapResponse setTotalResources (long resources) {
+ this.totalResources = resources;
return this;
};
/**
- * Increment the total number of texts the total number
+ * Increment the total number of resources the total number
* of results occur in by a certain value.
*
- * @param incr The number of texts the total number of
+ * @param incr The number of resources the total number of
* results occur in should be incremented by.
* (I don't care that this isn't English!)
* @return {@link KorapResponse} object for chaining.
*/
- public KorapResponse incrTotalTexts (int i) {
- if (this.totalTexts < 0)
- this.totalTexts = i;
+ public KorapResponse incrTotalResources (int i) {
+ if (this.totalResources < 0)
+ this.totalResources = i;
else
- this.totalTexts += i;
+ this.totalResources += i;
return this;
};
@@ -350,8 +350,8 @@
json.put("benchmark", this.getBenchmark());
// totalTexts is set
- if (this.totalTexts != -2)
- json.put("totalTexts", this.totalTexts);
+ if (this.totalResources != -2)
+ json.put("totalResources", this.totalResources);
// totalResults is set
if (this.totalResults != -2)
diff --git a/src/main/java/de/ids_mannheim/korap/response/Notifications.java b/src/main/java/de/ids_mannheim/korap/response/Notifications.java
index c3d7edd..8ecf0b3 100644
--- a/src/main/java/de/ids_mannheim/korap/response/Notifications.java
+++ b/src/main/java/de/ids_mannheim/korap/response/Notifications.java
@@ -421,9 +421,10 @@
/**
- * Serialize Notifications as a JsonNode.
+ * Serialize Notifications as a {@link JsonNode}.
*
- * @return JsonNode representation of all warnings, errors, and messages
+ * @return {@link JsonNode} representation of all warnings,
+ * errors, and messages.
*/
public JsonNode toJsonNode () {
ObjectNode json = mapper.createObjectNode();
diff --git a/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java b/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java
index b76adbe..bee4da5 100644
--- a/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java
+++ b/src/test/java/de/ids_mannheim/korap/collection/TestKorapCollectionJSON.java
@@ -20,49 +20,66 @@
@Test
public void collection1 () {
- String metaQuery = _getJSONString("collection_1.jsonld");
- KorapCollection kc = new KorapCollection(metaQuery);
- assertEquals(kc.toString(), "filter with QueryWrapperFilter(+pubDate:20000101); ");
+ String metaQuery = _getJSONString("collection_1.jsonld");
+ KorapCollection kc = new KorapCollection(metaQuery);
+ assertEquals(
+ kc.toString(),
+ "filter with QueryWrapperFilter(+pubDate:20000101); "
+ );
};
@Test
public void collection2 () {
- String metaQuery = _getJSONString("collection_2.jsonld");
- KorapCollection kc = new KorapCollection(metaQuery);
- assertEquals(kc.toString(), "filter with QueryWrapperFilter(+(+pubDate:[19900000 TO 99999999] +pubDate:[0 TO 20061099])); ");
+ String metaQuery = _getJSONString("collection_2.jsonld");
+ KorapCollection kc = new KorapCollection(metaQuery);
+ assertEquals(
+ kc.toString(),
+ "filter with QueryWrapperFilter(+(+pubDate:"+
+ "[19900000 TO 99999999] +pubDate:[0 TO 20061099])); "
+ );
};
+
@Test
public void collection3 () {
- String metaQuery = _getJSONString("collection_3.jsonld");
- KorapCollection kc = new KorapCollection(metaQuery);
- assertEquals(kc.toString(), "");
+ String metaQuery = _getJSONString("collection_3.jsonld");
+ KorapCollection kc = new KorapCollection(metaQuery);
+ assertEquals(kc.toString(), "");
};
+
@Test
public void collection5 () {
- String metaQuery = _getJSONString("collection_5.jsonld");
- KorapCollection kc = new KorapCollection(metaQuery);
- assertEquals(kc.toString(), "filter with QueryWrapperFilter(+(pubDate:[19900000 TO 99999999] title:Mannheim)); ");
+ String metaQuery = _getJSONString("collection_5.jsonld");
+ KorapCollection kc = new KorapCollection(metaQuery);
+ assertEquals(
+ kc.toString(),
+ "filter with QueryWrapperFilter(+(pubDate:"+
+ "[19900000 TO 99999999] title:Mannheim)); "
+ );
};
+
@Test
public void nocollectiontypegiven () {
- String metaQuery = _getJSONString("multiterm_rewrite_collection.jsonld");
- KorapCollection kc = new KorapCollection(metaQuery);
- assertEquals(701, kc.getError(0).getCode());
+ String metaQuery = _getJSONString("multiterm_rewrite_collection.jsonld");
+ KorapCollection kc = new KorapCollection(metaQuery);
+ assertEquals(701, kc.getError(0).getCode());
};
- @Ignore
+ @Test
public void noCollection () {
- String metaQuery = _getJSONString("no_collection.jsonld");
- // TODO!!!
- // Use KorapSearch and test
+ String metaQuery = _getJSONString("no_collection.jsonld");
+ KorapCollection kc = new KorapCollection(metaQuery);
+ assertEquals(
+ "filter with QueryWrapperFilter(+corpusID:WPD); ",
+ kc.toString()
+ );
};
private String _getJSONString (String file) {
- return getString(getClass().getResource(path + file).getFile());
+ return getString(getClass().getResource(path + file).getFile());
};
};