JSON deserialization for queries
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index 905199b..4044bfc 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -1,13 +1,16 @@
package de.ids_mannheim.korap;
-import org.apache.lucene.search.spans.SpanQuery;
-
import de.ids_mannheim.korap.query.wrap.*;
+import de.ids_mannheim.korap.util.QueryException;
+
+import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.util.automaton.RegExp;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.*;
+import java.io.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -20,6 +23,7 @@
*/
public class KorapQuery {
private String field;
+ private ObjectMapper json;
// Logger
private final static Logger log = LoggerFactory.getLogger(KorapQuery.class);
@@ -30,48 +34,119 @@
*/
public KorapQuery (String field) {
this.field = field;
+ this.json = new ObjectMapper();
};
- public SpanQueryWrapperInterface fromJSON (String json) {
- // Todo:
- return this.seg("s:test");
+ public SpanQueryWrapperInterface fromJSON (String jsonString) throws QueryException {
+ JsonNode json;
+ try {
+ json = this.json.readValue(jsonString, JsonNode.class);
+ }
+ catch (IOException e) {
+ throw new QueryException(e.getMessage());
+ };
+
+ 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
- public SpanQueryWrapperInterface fromJSON (JsonNode json) {
+ // TODO: Exception messages are horrible!
+ public SpanQueryWrapperInterface fromJSON (JsonNode json) throws QueryException {
+
+ if (!json.has("@type")) {
+ throw new QueryException("JSON-LD group has no @type attribute");
+ };
+
String type = json.get("@type").asText();
- if (type.equals("korap:group")) {
+
+ switch (type) {
+
+ case "korap:group":
+ SpanClassQueryWrapper classWrapper;
+
+ if (!json.has("relation")) {
+ if (json.has("class")) {
+ return new SpanClassQueryWrapper(
+ this.fromJSON(json.get("operands").get(0)),
+ json.get("class").asInt(0)
+ );
+ }
+ throw new QueryException("Group needs a relation or a class");
+ };
+
String relation = json.get("relation").asText();
+ if (!json.has("operands"))
+ throw new QueryException("Operation needs operands");
+
// Alternation
- if (relation.equals("or")) {
+ switch (relation) {
+
+ case "or":
+
SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
for (JsonNode operand : json.get("operands")) {
ssaq.or(this.fromJSON(operand));
};
+ if (json.has("class")) {
+ return new SpanClassQueryWrapper(ssaq, json.get("class").asInt(0));
+ };
return ssaq;
- }
- else {
- System.err.println("Unknown element");
+
+ case "position":
+ if (!json.has("position"))
+ throw new QueryException("Operation needs position specification");
+
+ // temporary
+ if (json.get("position").asText().equals("contains") || json.get("position").asText().equals("within")) {
+ return new SpanWithinQueryWrapper(
+ this.fromJSON(json.get("operands").get(0)),
+ this.fromJSON(json.get("operands").get(1))
+ );
+ };
+ throw new QueryException("Unknown position type "+json.get("position").asText());
+
+ case "shrink":
+ int number = 0;
+ // temporary
+ if (json.has("shrink"))
+ number = json.get("shrink").asInt();
+
+ return new SpanMatchModifyQueryWrapper(this.fromJSON(json.get("operands").get(0)), number);
};
- }
- else if (type.equals("korap:token")) {
- SpanSegmentQueryWrapper ssqw = new SpanSegmentQueryWrapper(this.field);
+ throw new QueryException("Unknown group relation");
+
+ case "korap:token":
JsonNode value = json.get("@value");
+ SpanSegmentQueryWrapper ssegqw = new SpanSegmentQueryWrapper(this.field);
type = value.get("@type").asText();
if (type.equals("korap:term")) {
- if (value.get("relation").asText().equals("=")) {
- ssqw.with(value.get("@value").asText());
+ switch (value.get("relation").asText()) {
+ case "=":
+ ssegqw.with(value.get("@value").asText());
+ return ssegqw;
+ case "!=":
+ throw new QueryException("Term relation != not yet supported");
};
- }
- else {
- System.err.println("Unknown type");
+ throw new QueryException("Unknown term relation");
};
+ throw new QueryException("Unknown token type");
- return ssqw;
- }
- return this.seg("s:test");
+ case "korap:sequence":
+ if (!json.has("operands"))
+ throw new QueryException("SpanSequenceQuery needs operands");
+
+ SpanSequenceQueryWrapper sseqqw = new SpanSequenceQueryWrapper(this.field);
+ for (JsonNode operand : json.get("operands")) {
+ sseqqw.append(this.fromJSON(operand));
+ };
+ return sseqqw;
+ };
+ throw new QueryException("Unknown serialized query type: " + type);
};
@@ -236,8 +311,6 @@
return new SpanWithinQueryWrapper(element, embedded);
};
-
-
// Class
public SpanClassQueryWrapper _ (byte number, SpanQueryWrapperInterface element) {
return new SpanClassQueryWrapper(element, number);
diff --git a/src/main/java/de/ids_mannheim/korap/KorapSearch.java b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
index d5e0c51..d0be889 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapSearch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
@@ -7,6 +7,7 @@
import de.ids_mannheim.korap.KorapCollection;
import de.ids_mannheim.korap.KorapIndex;
import de.ids_mannheim.korap.KorapResult;
+import de.ids_mannheim.korap.util.QueryException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
@@ -85,6 +86,8 @@
this.query = new KorapQuery("tokens").fromJSON(rootNode.get("query")).toQuery();
}
catch (IOException e) {
+ }
+ catch (QueryException e) {
};
};
diff --git a/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java b/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
new file mode 100644
index 0000000..9917184
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/query/TestKorapQueryJSON.java
@@ -0,0 +1,131 @@
+import java.util.*;
+import java.io.*;
+
+import org.apache.lucene.search.spans.SpanQuery;
+import de.ids_mannheim.korap.query.wrap.SpanQueryWrapperInterface;
+
+import de.ids_mannheim.korap.KorapQuery;
+import de.ids_mannheim.korap.util.QueryException;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.Ignore;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestKorapQueryJSON {
+
+ @Ignore
+ public void queryJSONBsp1 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp1.json").getFile());
+
+ // ([base=foo]|[base=bar])[base=foobar]
+ assertEquals(sqwi.toQuery().toString(), "");
+ };
+
+ @Test
+ public void queryJSONBsp1b () {
+
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp1b.json").getFile());
+
+ // [base=foo]|([base=foo][base=bar]) meta author=Goethe&year=1815
+ assertEquals(sqwi.toQuery().toString(), "spanOr([tokens:base:foo, spanNext(tokens:base:foo, tokens:base:bar)])");
+ };
+
+
+ @Test
+ public void queryJSONBsp2 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp2.json").getFile());
+
+ // ([base=foo]|[base=bar])[base=foobar]
+ assertEquals(sqwi.toQuery().toString(), "spanNext(spanOr([tokens:base:foo, tokens:base:bar]), tokens:base:foobar)");
+ };
+
+ @Test
+ public void queryJSONBsp3 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp3.json").getFile());
+
+ // shrink({[base=Mann]})
+ assertEquals(sqwi.toQuery().toString(), "shrink(0: {0: tokens:base:Mann})");
+ };
+
+ @Test
+ public void queryJSONBsp4 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp4.json").getFile());
+
+ // shrink({[base=foo]}[orth=bar])
+ assertEquals(sqwi.toQuery().toString(), "shrink(0: spanNext({0: tokens:base:foo}, tokens:orth:bar))");
+ };
+
+ @Test
+ public void queryJSONBsp5 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp5.json").getFile());
+
+ // shrink(1:[base=Der]{1:[base=Mann]})
+ assertEquals(sqwi.toQuery().toString(), "shrink(1: spanNext(tokens:base:Der, {1: tokens:base:Mann}))");
+ };
+
+ @Test
+ public void queryJSONBsp6 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp6.json").getFile());
+
+ // [base=katze]
+ assertEquals(sqwi.toQuery().toString(), "tokens:base:Katze");
+ };
+
+ @Ignore
+ public void queryJSONBsp7 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp7.json").getFile());
+
+ // [!base=Katze]
+ assertEquals(sqwi.toQuery().toString(), "");
+ };
+
+ @Ignore
+ public void queryJSONBsp8 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp8.json").getFile());
+
+ // [!base=Katze]
+ assertEquals(sqwi.toQuery().toString(), "");
+ };
+
+ /*
+ @Test
+ public void queryJSONBsp9 () {
+ SpanQueryWrapperInterface sqwi = jsonQuery(getClass().getResource("/queries/bsp9.json").getFile());
+
+ // [base=Katze&orth=Katzen]
+ assertEquals(sqwi.toQuery().toString(), "");
+ };
+ */
+
+ public static String getString (String path) {
+ StringBuilder contentBuilder = new StringBuilder();
+ try {
+ BufferedReader in = new BufferedReader(new FileReader(path));
+ String str;
+ while ((str = in.readLine()) != null) {
+ contentBuilder.append(str);
+ };
+ in.close();
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ return contentBuilder.toString();
+ };
+
+ public static SpanQueryWrapperInterface jsonQuery (String jsonFile) {
+ SpanQueryWrapperInterface sqwi;
+
+ try {
+ String json = getString(jsonFile);
+ sqwi = new KorapQuery("tokens").fromJSON(json);
+ }
+ catch (QueryException e) {
+ fail(e.getMessage());
+ sqwi = new KorapQuery("tokens").seg("???");
+ };
+ return sqwi;
+ };
+};
\ No newline at end of file
diff --git a/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java b/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
index 705bf33..0d62975 100644
--- a/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
+++ b/src/test/java/de/ids_mannheim/korap/search/TestKorapSearch.java
@@ -90,29 +90,4 @@
assertEquals(6, kr.totalResults());
assertEquals(kr.getMatch(0).getSnippetBrackets(), "... dem [Buchstaben] A ...");
};
-
- @Test
- public void searchJSON () throws IOException {
-
- String jsonFile = getClass().getResource("/queries/bsp1.json").getFile();
-
- KorapSearch ks = new KorapSearch(getString(jsonFile));
-
- // assertEquals(ks.getQuery().toString(), "");
- };
-
- public static String getString (String path) {
- StringBuilder contentBuilder = new StringBuilder();
- try {
- BufferedReader in = new BufferedReader(new FileReader(path));
- String str;
- while ((str = in.readLine()) != null) {
- contentBuilder.append(str);
- };
- in.close();
- } catch (IOException e) {
- }
- return contentBuilder.toString();
- };
-
};
diff --git a/src/test/resources/queries/readme.txt b/src/test/resources/queries/readme.txt
index 5cfd658..36745ce 100644
--- a/src/test/resources/queries/readme.txt
+++ b/src/test/resources/queries/readme.txt
@@ -1,4 +1,4 @@
-bsp1.json: [base=foo]|([base=foo][base=bar]) meta author=Goethe&year=1815
+bsp1.json: [base=foo]|([base=foo][base=bar])* meta author=Goethe&year=1815
bsp2.json: ([base=foo]|[base=bar])[base=foobar]
bsp3.json: shrink({[base=Mann]})
bsp4.json: shrink({[base=foo]}[orth=bar])