started work on operators in AQL
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java b/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java
index 0c29bfa..04e6b21 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/AqlTree.java
@@ -2,6 +2,7 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
@@ -70,6 +71,12 @@
*/
LinkedList<Integer> objectsToPop = new LinkedList<Integer>();
Integer stackedObjects = 0;
+ /**
+ * Keeps track of references to nodes that are operands of groups (e.g. tree relations). Those nodes appear on the top level of the parse tree
+ * but are to be integrated into the AqlTree at a later point (namely as operands of the respective group). Therefore, store references to these
+ * nodes here and exclude the operands from being written into the query map individually.
+ */
+ private LinkedList<String> operandOnlyNodeRefs = new LinkedList<String>();
public static boolean verbose = false;
/**
@@ -137,6 +144,7 @@
processNode(tree);
}
+ @SuppressWarnings("unchecked")
private void processNode(ParseTree node) {
// Top-down processing
if (visited.contains(node)) return;
@@ -170,66 +178,103 @@
}
if (nodeCat.equals("andTopExpr")) {
- if (node.getChildCount() > 1) {
- LinkedHashMap<String, Object> andGroup = makeGroup("and");
- objectStack.push(andGroup);
- stackedObjects++;
- putIntoSuperObject(andGroup,1);
+ // Before processing any child expr node, check if it has one or more "n_ary_linguistic_term" nodes.
+ // Those nodes may use references to earlier established operand nodes.
+ // Those operand nodes are not to be included into the query map individually but
+ // naturally as operands of the relations/groups introduced by the
+ // n_ary_linguistic_term node. For that purpose, this section mines all used references
+ // and stores them in a list for later reference.
+ for (ParseTree exprNode : getChildrenWithCat(node,"expr")) {
+ List<ParseTree> lingTermNodes = new ArrayList<ParseTree>();
+ lingTermNodes.addAll(getChildrenWithCat(exprNode, "unary_linguistic_term"));
+ lingTermNodes.addAll(getChildrenWithCat(exprNode, "n_ary_linguistic_term"));
+ // Traverse refOrNode nodes under *ary_linguistic_term nodes and extract references
+ for (ParseTree lingTermNode : lingTermNodes) {
+ for (ParseTree refOrNode : getChildrenWithCat(lingTermNode, "refOrNode")) {
+ operandOnlyNodeRefs.add(refOrNode.getChild(0).toStringTree(parser).substring(1));
+ }
+ }
}
+// // TODO first check all 'expr' children for n_ary_linguistic_terms (see below)
+// if (node.getChildCount() > 1) {
+// LinkedHashMap<String, Object> andGroup = makeGroup("and");
+// objectStack.push(andGroup);
+// stackedObjects++;
+// putIntoSuperObject(andGroup,1);
+// }
}
+ // establish new variables or relations between vars
if (nodeCat.equals("expr")) {
- // establish new variables or relations between vars
-
+ // Check if expr node has one or more "n_ary_linguistic_term" nodes.
+ // Those nodes may use references to earlier established operand nodes.
+ // Those operand nodes are not to be included into the query map individually but
+ // naturally as operands of the relations/groups introduced by the
+ // n_ary_linguistic_term node. For that purpose, this section mines all used references
+ // and stores them in a list for later reference.
+// List<ParseTree> lingTermNodes = new ArrayList<ParseTree>();
+// lingTermNodes.addAll(getChildrenWithCat(node, "unary_linguistic_term"));
+// lingTermNodes.addAll(getChildrenWithCat(node, "n_ary_linguistic_term"));
+// // Traverse refOrNode nodes under *ary_linguistic_term nodes and extract references
+// for (ParseTree lingTermNode : lingTermNodes) {
+// for (ParseTree refOrNode : getChildrenWithCat(lingTermNode, "refOrNode")) {
+// operandOnlyNodeRefs.add(refOrNode.getChild(0).toStringTree(parser).substring(1));
+// }
+// }
+ }
+
+ if (nodeCat.equals("n_ary_linguistic_term") || nodeCat.equals("unary_linguistic_term")) {
+ // get referenced operands
+ // TODO generalize operator
+ // TODO capture variableExprs
+ LinkedHashMap<String, Object> group = makeGroup("treeRelation");
+ group.put("treeRelation", getNodeCat(node.getChild(1).getChild(0)));
+ List<Object> operands = (List<Object>) group.get("operands");
+ for (ParseTree refOrNode : getChildrenWithCat(node, "refOrNode")) {
+ String ref = refOrNode.getChild(0).toStringTree(parser).substring(1);
+ operands.add(variableReferences.get(ref));
+ }
+ putIntoSuperObject(group);
}
if (nodeCat.equals("variableExpr")) {
// simplex word or complex assignment (like qname = textSpec)?
- if (node.getChildCount()==1) { // simplex
- String firstChildNodeCat = getNodeCat(node.getChild(0));
- if (firstChildNodeCat.equals("node")) {
- LinkedHashMap<String, Object> span = makeSpan();
- putIntoSuperObject(span);
- variableReferences.put(variableCounter.toString(), span);
- variableCounter++;
- } else if (firstChildNodeCat.equals("tok")) {
- // TODO
- } else if (firstChildNodeCat.equals("qName")) { // only (foundry/)?layer specified
- // TODO may also be token!
- LinkedHashMap<String, Object> span = makeSpan();
- span.putAll(parseQNameNode(node.getChild(0)));
- putIntoSuperObject(span);
- variableReferences.put(variableCounter.toString(), span);
- variableCounter++;
+ String firstChildNodeCat = getNodeCat(node.getChild(0));
+ LinkedHashMap<String, Object> object = null;
+ if (firstChildNodeCat.equals("node")) {
+ object = makeSpan();
+ } else if (firstChildNodeCat.equals("tok")) {
+ object = makeToken();
+ LinkedHashMap<String, Object> term = makeTerm();
+ object.put("wrap", term);
+ } else if (firstChildNodeCat.equals("qName")) { // only (foundry/)?layer specified
+ // TODO may also be token!
+ object = makeSpan();
+ object.putAll(parseQNameNode(node.getChild(0)));
+ } else if (firstChildNodeCat.equals("textSpec")) {
+ object = makeToken();
+ LinkedHashMap<String, Object> term = makeTerm();
+ object.put("wrap", term);
+ term.putAll(parseTextSpec(node.getChild(0)));
+ }
+
+ if (node.getChildCount() == 3) { // (foundry/)?layer=key specification
+ if (firstChildNodeCat.equals("tok")) {
+ HashMap<String, Object> term = (HashMap<String, Object>) object.get("wrap");
+ term.putAll(parseTextSpec(node.getChild(2)));
+ term.put("match", parseMatchOperator(node.getChild(1)));
+ } else {
+ object.putAll(parseTextSpec(node.getChild(2)));
+ object.put("match", parseMatchOperator(node.getChild(1)));
}
- } else if (node.getChildCount() == 3) { // (foundry/)?layer=key specification
- LinkedHashMap<String, Object> span = makeSpan();
- // get foundry and layer
- span.putAll(parseQNameNode(node.getChild(0)));
- // get key
- span.putAll(parseVarKey(node.getChild(2)));
- // get relation (match or no match)
- span.put("match", parseMatchOperator(node.getChild(1)));
- putIntoSuperObject(span);
- variableReferences.put(variableCounter.toString(), span);
+ }
+
+ if (object != null) {
+ if (! operandOnlyNodeRefs.contains(variableCounter.toString())) putIntoSuperObject(object);
+ variableReferences.put(variableCounter.toString(), object);
variableCounter++;
}
}
-
- if (nodeCat.equals("regex")) {
- // mother node can be start or other
- // if start: make token root of tree
- // else: integrate into super object
- if (openNodeCats.get(1).equals("start")) {
- LinkedHashMap<String, Object> token = makeToken();
- LinkedHashMap<String, Object> term = makeTerm();
- token.put("wrap", term);
- term.put("type", "type:regex");
- term.put("key", node.getChild(1).toStringTree(parser));
- }
- }
-
-
objectsToPop.push(stackedObjects);
@@ -244,30 +289,36 @@
ParseTree child = node.getChild(i);
processNode(child);
}
-
-
+
/*
**************************************************************
* Stuff that happens after processing the children of a node *
**************************************************************
*/
-
if (!objectsToPop.isEmpty()) {
for (int i=0; i<objectsToPop.pop(); i++) {
objectStack.pop();
}
}
-
-
-
openNodeCats.pop();
-
}
+ private Map<? extends String, ? extends Object> parseTextSpec(ParseTree node) {
+ HashMap<String, Object> term = new HashMap<String, Object>();
+ if (hasChild(node, "regex")) {
+ term.put("type", "type:regex");
+ term.put("key", node.getChild(0).getChild(0).toStringTree(parser).replaceAll("/", ""));
+ } else {
+ term.put("key", node.getChild(1).toStringTree(parser));
+ }
+ term.put("match", "match:eq");
+ return term;
+ }
+
/**
* Parses the match operator (= or !=)
* @param node
@@ -299,6 +350,7 @@
private LinkedHashMap<String, Object> parseQNameNode(ParseTree node) {
+ System.err.println(getNodeCat(node));
LinkedHashMap<String, Object> fields = new LinkedHashMap<String, Object>();
if (node.getChildCount() == 1) { // only layer specification
fields.put("layer", node.getChild(0).toStringTree(parser));
@@ -390,9 +442,14 @@
"tiger/pos=\"NN\" > node",
"ref#node & pos=\"NN\" > #ref",
"node & tree/pos=\"NN\"",
- "/node/"
+ "/node/",
+ "\"Mann\"",
+ "tok!=/Frau/",
+ "node",
+ "treetagger/pos=\"NN\"",
+ "node & node & #2 > #1"
};
- AqlTree.verbose=true;
+// AqlTree.verbose=true;
for (String q : queries) {
try {
System.out.println(q);
diff --git a/src/test/java/AqlTreeTest.java b/src/test/java/AqlTreeTest.java
new file mode 100644
index 0000000..27bb1dd
--- /dev/null
+++ b/src/test/java/AqlTreeTest.java
@@ -0,0 +1,95 @@
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import de.ids_mannheim.korap.query.serialize.AqlTree;
+import de.ids_mannheim.korap.query.serialize.PoliqarpPlusTree;
+import de.ids_mannheim.korap.util.QueryException;
+
+public class AqlTreeTest {
+
+ AqlTree aqlt;
+ String map;
+ private String query;
+
+ private boolean equalsQueryContent(String res, String query) throws QueryException {
+ res = res.replaceAll(" ", "");
+ aqlt = new AqlTree(query);
+ String queryMap = aqlt.getRequestMap().get("query").toString().replaceAll(" ", "");
+ return res.equals(queryMap);
+ }
+
+ @Test
+ public void testContext() throws QueryException {
+ String contextString = "http://ids-mannheim.de/ns/KorAP/json-ld/v0.1/context.jsonld";
+ aqlt = new AqlTree("Test");
+ assertEquals(contextString.replaceAll(" ", ""), aqlt.getRequestMap().get("@context").toString().replaceAll(" ", ""));
+ }
+
+ @Test
+ public void testSingleTokens() throws QueryException {
+ // "Mann"
+ query = "\"Mann\"";
+ String token1 = "{@type=korap:token, wrap={@type=korap:term, match=match:eq, key=Mann}}";
+ assertTrue(equalsQueryContent(token1, query));
+
+ // [orth!=Frau]
+ query = "tok!=\"Frau\"";
+ String token2 = "{@type=korap:token, wrap={@type=korap:term, match=match:ne, key=Frau}}";
+ assertTrue(equalsQueryContent(token2, query));
+
+ // Mann
+ query = "Mann";
+ String token4 = "{@type=korap:span, layer=Mann}";
+ assertTrue(equalsQueryContent(token4, query));
+ }
+
+ @Test
+ public void testSpans() throws QueryException {
+ query = "node";
+ String span1 =
+ "{@type=korap:span}";
+ aqlt = new AqlTree(query);
+ map = aqlt.getRequestMap().get("query").toString();
+ assertEquals(span1.replaceAll(" ", ""), map.replaceAll(" ", ""));
+ }
+
+ @Test
+ public void testRegex() throws QueryException {
+ query = "/Mann/";
+ String regex1 = "{@type=korap:token, wrap={@type=korap:term, match=match:eq, type=type:regex, key=Mann}}";
+ aqlt = new AqlTree(query);
+ map = aqlt.getRequestMap().get("query").toString();
+ assertEquals(regex1.replaceAll(" ", ""), map.replaceAll(" ", ""));
+ }
+
+ @Test
+ public void testLayers() throws QueryException {
+ query = "cnx/cat=\"NP\"";
+ String layers1 = "{@type=korap:span, foundry=cnx, layer=cat, match=match:eq, key=NP}";
+ aqlt = new AqlTree(query);
+ map = aqlt.getRequestMap().get("query").toString();
+ assertEquals(layers1.replaceAll(" ", ""), map.replaceAll(" ", ""));
+
+ query = "treetagger/pos=\"NN\"";
+ String layers2 = "{@type=korap:token, wrap={@type=korap:term, foundry=treetagger, layer=pos, key=NN, match=match:eq}}";
+ aqlt = new AqlTree(query);
+ map = aqlt.getRequestMap().get("query").toString();
+ assertEquals(layers2.replaceAll(" ", ""), map.replaceAll(" ", ""));
+ }
+
+ @Test
+ public void testSimpleDominance() throws QueryException {
+ query = "node & node & #2 > #1";
+ String dom1 =
+ "{@type=korap:group, operation=operation:treeRelation, operands=[" +
+ "{@type=korap:span}," +
+ "{@type=korap:span}" +
+ "], treeRelation=dominance}";
+ aqlt = new AqlTree(query);
+ map = aqlt.getRequestMap().get("query").toString();
+ assertEquals(dom1.replaceAll(" ", ""), map.replaceAll(" ", ""));
+ }
+
+}
+
diff --git a/src/test/java/CosmasTreeTest.java b/src/test/java/CosmasTreeTest.java
index b084bb4..10b6ed8 100644
--- a/src/test/java/CosmasTreeTest.java
+++ b/src/test/java/CosmasTreeTest.java
@@ -11,18 +11,6 @@
String map;
String query;
- private boolean equalsContent(String str, Object map) {
- str = str.replaceAll(" ", "");
- String mapStr = map.toString().replaceAll(" ", "");
- return str.equals(mapStr);
- }
-
- private boolean equalsQueryContent(String res, String query) throws QueryException {
- res = res.replaceAll(" ", "");
- ct = new CosmasTree(query);
- String queryMap = ct.getRequestMap().get("query").toString().replaceAll(" ", "");
- return res.equals(queryMap);
- }
@Test
public void testContext() throws QueryException {
diff --git a/src/test/java/PoliqarpPlusTreeTest.java b/src/test/java/PoliqarpPlusTreeTest.java
index 69d9293..3fab91f 100644
--- a/src/test/java/PoliqarpPlusTreeTest.java
+++ b/src/test/java/PoliqarpPlusTreeTest.java
@@ -2,7 +2,6 @@
import org.junit.Test;
-import de.ids_mannheim.korap.query.serialize.CosmasTree;
import de.ids_mannheim.korap.query.serialize.PoliqarpPlusTree;
import de.ids_mannheim.korap.util.QueryException;
@@ -11,11 +10,6 @@
PoliqarpPlusTree ppt;
String map;
- private boolean equalsContent(String str, Object map) {
- str = str.replaceAll(" ", "");
- String mapStr = map.toString().replaceAll(" ", "");
- return str.equals(mapStr);
- }
private boolean equalsQueryContent(String res, String query) throws QueryException {
res = res.replaceAll(" ", "");