Cleanup of KorapMatch
diff --git a/CHANGES b/CHANGES
index 8006069..e76855a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+0.42 2014-09-17
+ - [cleanup] Extracted private classes from KorapMatch (diewald)
+
0.41 2014-09-17
- [feature] getStartPos(classNr) and getEndPos(classNr)
in KorapMatch (diewald)
diff --git a/pom.xml b/pom.xml
index ffe154e..8a3a06f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
<groupId>KorAP-modules</groupId>
<artifactId>KorAP-lucene-index</artifactId>
- <version>0.41</version>
+ <version>0.42</version>
<packaging>jar</packaging>
<name>KorAP-lucene-index</name>
diff --git a/src/main/java/de/ids_mannheim/korap/KorapIndex.java b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
index 26cd3ca..6343456 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapIndex.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
@@ -75,7 +75,6 @@
import de.ids_mannheim.korap.index.TermInfo;
import de.ids_mannheim.korap.index.SpanInfo;
import de.ids_mannheim.korap.index.SearchContext;
-import de.ids_mannheim.korap.index.MatchIdentifier;
import de.ids_mannheim.korap.query.SpanElementQuery;
import de.ids_mannheim.korap.index.MatchCollector;
import de.ids_mannheim.korap.util.QueryException;
diff --git a/src/main/java/de/ids_mannheim/korap/KorapMatch.java b/src/main/java/de/ids_mannheim/korap/KorapMatch.java
index 62fbebb..78267a2 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapMatch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapMatch.java
@@ -2,7 +2,6 @@
import java.util.*;
import java.io.*;
-import java.lang.StringBuffer;
import java.nio.ByteBuffer;
import com.fasterxml.jackson.annotation.*;
@@ -15,9 +14,11 @@
import de.ids_mannheim.korap.index.SearchContext;
import de.ids_mannheim.korap.document.KorapPrimaryData;
-import static de.ids_mannheim.korap.util.KorapHTML.*;
-import de.ids_mannheim.korap.index.MatchIdentifier;
-import de.ids_mannheim.korap.index.PosIdentifier;
+import de.ids_mannheim.korap.match.HighlightCombinator;
+import de.ids_mannheim.korap.match.HighlightCombinatorElement;
+import de.ids_mannheim.korap.match.Relation;
+import de.ids_mannheim.korap.match.MatchIdentifier;
+import de.ids_mannheim.korap.match.PosIdentifier;
import de.ids_mannheim.korap.query.SpanElementQuery;
import org.slf4j.Logger;
@@ -75,9 +76,9 @@
@JsonIgnore
public int localDocID = -1;
- HashMap<Integer, String> annotationNumber = new HashMap<>(16);
- HashMap<Integer, Relation> relationNumber = new HashMap<>(16);
- HashMap<Integer, Integer> identifierNumber = new HashMap<>(16);
+ private HashMap<Integer, String> annotationNumber = new HashMap<>(16);
+ private HashMap<Integer, Relation> relationNumber = new HashMap<>(16);
+ private HashMap<Integer, Integer> identifierNumber = new HashMap<>(16);
// -1 is match highlight
int annotationNumberCounter = 256;
@@ -191,18 +192,6 @@
};
- /**
- * Private class of relations.
- */
- private class Relation {
- public int ref;
- public String annotation;
- public Relation (String annotation, int ref) {
- this.annotation = annotation;
- this.ref = ref;
- };
- };
-
// TODO: Here are offsets and highlight offsets!
// <> payloads have 12 bytes (iii) or 8!?
// highlightoffsets have 11 bytes (iis)!
@@ -925,311 +914,7 @@
};
};
- /*
- Private class for elements with highlighting information
- */
- private class HighlightCombinatorElement {
- // Type 0: Textual data
- // Type 1: Opening
- // Type 2: Closing
- private byte type;
-
- private int number = 0;
-
- private String characters;
- private boolean terminal = true;
-
- // Constructor for highlighting elements
- public HighlightCombinatorElement (byte type, int number) {
- this.type = type;
- this.number = number;
- };
-
- // Constructor for highlighting elements,
- // that may not be terminal, i.e. they were closed and will
- // be reopened for overlapping issues.
- public HighlightCombinatorElement (byte type, int number, boolean terminal) {
- this.type = type;
- this.number = number;
- this.terminal = terminal;
- };
-
- // Constructor for textual data
- public HighlightCombinatorElement (String characters) {
- this.type = (byte) 0;
- this.characters = characters;
- };
-
- // Return html fragment for this combinator element
- public String toHTML (KorapMatch match, FixedBitSet level, byte[] levelCache) {
- // Opening
- if (this.type == 1) {
- StringBuilder sb = new StringBuilder();
- if (this.number == -1) {
- sb.append("<span class=\"match\">");
- }
-
- else if (this.number < -1) {
- sb.append("<span xml:id=\"")
- .append(match.getPosID(
- identifierNumber.get(this.number)))
- .append("\">");
- }
-
- else if (this.number >= 256) {
- sb.append("<span ");
- if (this.number < 2048) {
- sb.append("title=\"")
- .append(annotationNumber.get(this.number))
- .append('"');
- }
- else {
- Relation rel = relationNumber.get(this.number);
- sb.append("xlink:title=\"")
- .append(rel.annotation)
- .append('"');
- sb.append(" xlink:type=\"simple\"");
- sb.append(" xlink:href=\"#");
- sb.append(match.getPosID(rel.ref));
- sb.append('"');
- };
- sb.append('>');
- }
- else {
- // Get the first free level slot
- byte pos;
- if (levelCache[this.number] != '\0') {
- pos = levelCache[this.number];
- }
- else {
- pos = (byte) level.nextSetBit(0);
- level.clear(pos);
- levelCache[this.number] = pos;
- };
- sb.append("<em class=\"class-")
- .append(this.number)
- .append(" level-")
- .append(pos)
- .append("\">");
- };
- return sb.toString();
- }
- // Closing
- else if (this.type == 2) {
- if (this.number <= -1 || this.number >= 256)
- return "</span>";
-
- if (this.terminal)
- level.set((int) levelCache[this.number]);
- return "</em>";
- };
-
- // HTML encode primary data
- return encodeHTML(this.characters);
- };
-
- // Return bracket fragment for this combinator element
- public String toBrackets () {
- if (this.type == 1) {
- StringBuilder sb = new StringBuilder();
-
- // Match
- if (this.number == -1) {
- sb.append("[");
- }
-
- // Identifier
- else if (this.number < -1) {
- sb.append("{#");
- sb.append(identifierNumber.get(this.number));
- sb.append(':');
- }
-
- // Highlight, Relation, Span
- else {
- sb.append("{");
- if (this.number >= 256) {
- if (this.number < 2048)
- sb.append(annotationNumber.get(this.number));
- else {
- Relation rel = relationNumber.get(this.number);
- sb.append(rel.annotation);
- sb.append('>').append(rel.ref);
- };
- sb.append(':');
- }
- else if (this.number != 0)
- sb.append(this.number).append(':');
- };
- return sb.toString();
- }
- else if (this.type == 2) {
- if (this.number == -1)
- return "]";
- return "}";
- };
- return this.characters;
- };
- };
-
- /*
- Private class for combining highlighting elements
- */
- private class HighlightCombinator {
- private LinkedList<HighlightCombinatorElement> combine;
- private LinkedList<Integer> balanceStack = new LinkedList<>();
- private ArrayList<Integer> tempStack = new ArrayList<>(32);
-
- // Empty constructor
- public HighlightCombinator () {
- this.combine = new LinkedList<>();
- };
-
- // Return the combination stack
- public LinkedList<HighlightCombinatorElement> stack () {
- return this.combine;
- };
-
- // get the first element (without removing)
- public HighlightCombinatorElement getFirst () {
- return this.combine.getFirst();
- };
-
- // get the last element (without removing)
- public HighlightCombinatorElement getLast () {
- return this.combine.getLast();
- };
-
- // get an element by index (without removing)
- public HighlightCombinatorElement get (int index) {
- return this.combine.get(index);
- };
-
- // Get the size of te combinator stack
- public short size () {
- return (short) this.combine.size();
- };
-
- // Add primary data to the stack
- public void addString (String characters) {
- this.combine.add(new HighlightCombinatorElement(characters));
- };
-
- // Add opening highlight combinator to the stack
- public void addOpen (int number) {
- this.combine.add(new HighlightCombinatorElement((byte) 1, number));
- this.balanceStack.add(number);
- };
-
- // Add closing highlight combinator to the stack
- public void addClose (int number) {
- HighlightCombinatorElement lastComb;
- this.tempStack.clear();
-
- // Shouldn't happen
- if (this.balanceStack.size() == 0) {
- if (DEBUG)
- log.trace("The balance stack is empty");
- return;
- };
-
- if (DEBUG) {
- StringBuilder sb = new StringBuilder(
- "Stack for checking with class "
- );
- sb.append(number).append(" is ");
- for (int s : this.balanceStack) {
- sb.append('[').append(s).append(']');
- };
- log.trace(sb.toString());
- };
-
- // class number of the last element
- int eold = this.balanceStack.removeLast();
-
- // the closing element is not balanced
- while (eold != number) {
-
- // Retrieve last combinator on stack
- lastComb = this.combine.peekLast();
-
- if (DEBUG)
- log.trace("Closing element is unbalanced - {} " +
- "!= {} with lastComb {}|{}|{}",
- eold,
- number,
- lastComb.type,
- lastComb.number,
- lastComb.characters);
-
- // combinator is opening and the number is not equal to the last
- // element on the balanceStack
- if (lastComb.type == 1 && lastComb.number == eold) {
-
- // Remove the last element - it's empty and uninteresting!
- this.combine.removeLast();
- }
-
- // combinator is either closing (??) or another opener
- else {
-
- if (DEBUG)
- log.trace("close element a) {}", eold);
-
- // Add a closer for the old element (this has following elements)
- this.combine.add(new HighlightCombinatorElement((byte) 2, eold, false));
- };
-
- // add this element number temporarily on the stack
- tempStack.add(eold);
-
- // Check next element
- eold = this.balanceStack.removeLast();
- };
-
- // Get last combinator on the stack
- lastComb = this.combine.peekLast();
-
- if (DEBUG) {
- log.trace("LastComb: " + lastComb.type + '|' + lastComb.number + '|' + lastComb.characters + " for " + number);
- log.trace("Stack for checking 2: {}|{}|{}|{}", lastComb.type, lastComb.number, lastComb.characters, number);
- };
-
- if (lastComb.type == 1 && lastComb.number == number) {
- while (lastComb.type == 1 && lastComb.number == number) {
- // Remove the damn thing - It's empty and uninteresting!
- this.combine.removeLast();
- lastComb = this.combine.peekLast();
- };
- }
- else {
- if (DEBUG)
- log.trace("close element b) {}", number);
-
- // Add a closer
- this.combine.add(new HighlightCombinatorElement((byte) 2, number));
- };
-
-
- // Fetch everything from the tempstack and reopen it
- for (int e : tempStack) {
- if (DEBUG)
- log.trace("Reopen element {}", e);
- combine.add(new HighlightCombinatorElement((byte) 1, e));
- balanceStack.add(e);
- };
- };
-
- // Get all combined elements as a string
- public String toString () {
- StringBuilder sb = new StringBuilder();
- for (HighlightCombinatorElement e : combine) {
- sb.append(e.toString()).append("\n");
- };
- return sb.toString();
- };
- };
private void _processHighlightSnippet (String clean,
ArrayList<int[]> stack) {
@@ -1237,8 +922,7 @@
if (DEBUG)
log.trace("--- Process Highlight snippet");
- int pos = 0,
- oldPos = 0;
+ int pos = 0, oldPos = 0;
this.snippetStack = new HighlightCombinator();
@@ -1288,12 +972,15 @@
StringBuilder sb = new StringBuilder();
+ // Snippet stack sizes
short start = (short) 0;
short end = this.snippetStack.size();
+
FixedBitSet level = new FixedBitSet(16);
level.set(0, 15);
byte[] levelCache = new byte[16];
+ // Get the first elem
HighlightCombinatorElement elem = this.snippetStack.getFirst();
// Create context
@@ -1350,7 +1037,7 @@
sb.append("... ");
for (HighlightCombinatorElement hce : this.snippetStack.stack()) {
- sb.append(hce.toBrackets());
+ sb.append(hce.toBrackets(this));
};
if (endMore)
@@ -1700,4 +1387,27 @@
this.span.remove(delete);
};
};
+
+
+ /*
+ * Get identifier based on class number
+ */
+ public int getClassID (int nr) {
+ return this.identifierNumber.get(nr);
+ };
+
+ /*
+ * Get annotation based on id
+ */
+ public String getAnnotationID (int nr) {
+ return this.annotationNumber.get(nr);
+ };
+
+
+ /*
+ * Get relation based on id
+ */
+ public Relation getRelationID (int nr) {
+ return this.relationNumber.get(nr);
+ };
};
diff --git a/src/main/java/de/ids_mannheim/korap/KorapResult.java b/src/main/java/de/ids_mannheim/korap/KorapResult.java
index cedf75c..fd70547 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapResult.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapResult.java
@@ -46,9 +46,7 @@
private final static Logger log = LoggerFactory.getLogger(KorapMatch.class);
// Empty result
- public KorapResult() {
- }
-
+ public KorapResult() {}
public KorapResult(String query,
int startIndex,
diff --git a/src/main/java/de/ids_mannheim/korap/index/DocIdentifier.java b/src/main/java/de/ids_mannheim/korap/match/DocIdentifier.java
similarity index 100%
rename from src/main/java/de/ids_mannheim/korap/index/DocIdentifier.java
rename to src/main/java/de/ids_mannheim/korap/match/DocIdentifier.java
diff --git a/src/main/java/de/ids_mannheim/korap/match/HighlightCombinator.java b/src/main/java/de/ids_mannheim/korap/match/HighlightCombinator.java
new file mode 100644
index 0000000..4cff483
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/match/HighlightCombinator.java
@@ -0,0 +1,183 @@
+package de.ids_mannheim.korap.match;
+
+import de.ids_mannheim.korap.KorapMatch;
+import de.ids_mannheim.korap.match.HighlightCombinatorElement;
+import java.util.*;
+import java.io.*;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ Public class for combining highlighting elements
+*/
+public class HighlightCombinator {
+
+ // Logger
+ private final static Logger log = LoggerFactory.getLogger(KorapMatch.class);
+
+ // This advices the java compiler to ignore all loggings
+ public static final boolean DEBUG = false;
+
+
+ private LinkedList<HighlightCombinatorElement> combine;
+ private LinkedList<Integer> balanceStack = new LinkedList<>();
+ private ArrayList<Integer> tempStack = new ArrayList<>(32);
+
+ // Empty constructor
+ public HighlightCombinator () {
+ this.combine = new LinkedList<>();
+ };
+
+ // Return the combination stack
+ public LinkedList<HighlightCombinatorElement> stack () {
+ return this.combine;
+ };
+
+ // get the first element (without removing)
+ public HighlightCombinatorElement getFirst () {
+ return this.combine.getFirst();
+ };
+
+ // get the last element (without removing)
+ public HighlightCombinatorElement getLast () {
+ return this.combine.getLast();
+ };
+
+ // get an element by index (without removing)
+ public HighlightCombinatorElement get (int index) {
+ return this.combine.get(index);
+ };
+
+ // Get the size of te combinator stack
+ public short size () {
+ return (short) this.combine.size();
+ };
+
+ // Add primary data to the stack
+ public void addString (String characters) {
+ this.combine.add(new HighlightCombinatorElement(characters));
+ };
+
+ // Add opening highlight combinator to the stack
+ public void addOpen (int number) {
+ this.combine.add(new HighlightCombinatorElement((byte) 1, number));
+ this.balanceStack.add(number);
+ };
+
+ // Add closing highlight combinator to the stack
+ public void addClose (int number) {
+ HighlightCombinatorElement lastComb;
+ this.tempStack.clear();
+
+ // Shouldn't happen
+ if (this.balanceStack.size() == 0) {
+ if (DEBUG)
+ log.trace("The balance stack is empty");
+ return;
+ };
+
+ // Just some debug information
+ if (DEBUG) {
+ StringBuilder sb = new StringBuilder("Stack for checking with class ");
+ sb.append(number).append(" is ");
+ for (int s : this.balanceStack) {
+ sb.append('[').append(s).append(']');
+ };
+ log.trace(sb.toString());
+ };
+
+ // class number of the last element
+ int eold = this.balanceStack.removeLast();
+
+ // the closing element is not balanced
+ while (eold != number) {
+
+ // Retrieve last combinator on stack
+ lastComb = this.combine.peekLast();
+
+ if (DEBUG)
+ log.trace("Closing element is unbalanced - {} " +
+ "!= {} with lastComb {}|{}|{}",
+ eold,
+ number,
+ lastComb.type,
+ lastComb.number,
+ lastComb.characters);
+
+ // combinator is opening and the number is not equal to the last
+ // element on the balanceStack
+ if (lastComb.type == 1 && lastComb.number == eold) {
+
+ // Remove the last element - it's empty and uninteresting!
+ this.combine.removeLast();
+ }
+
+ // combinator is either closing (??) or another opener
+ else {
+
+ if (DEBUG)
+ log.trace("close element a) {}", eold);
+
+ // Add a closer for the old element (this has following elements)
+ this.combine.add(new HighlightCombinatorElement((byte) 2, eold, false));
+ };
+
+ // add this element number temporarily on the stack
+ tempStack.add(eold);
+
+ // Check next element
+ eold = this.balanceStack.removeLast();
+ };
+
+ // Get last combinator on the stack
+ lastComb = this.combine.peekLast();
+
+ if (DEBUG) {
+ log.trace("LastComb: " +
+ lastComb.type +
+ '|' +
+ lastComb.number +
+ '|' + lastComb.characters +
+ " for " +
+ number);
+ log.trace("Stack for checking 2: {}|{}|{}|{}",
+ lastComb.type,
+ lastComb.number,
+ lastComb.characters,
+ number);
+ };
+
+ if (lastComb.type == 1 && lastComb.number == number) {
+ while (lastComb.type == 1 && lastComb.number == number) {
+ // Remove the damn thing - It's empty and uninteresting!
+ this.combine.removeLast();
+ lastComb = this.combine.peekLast();
+ };
+ }
+ else {
+ if (DEBUG)
+ log.trace("close element b) {}", number);
+
+ // Add a closer
+ this.combine.add(new HighlightCombinatorElement((byte) 2, number));
+ };
+
+ // Fetch everything from the tempstack and reopen it
+ for (int e : tempStack) {
+ if (DEBUG)
+ log.trace("Reopen element {}", e);
+ combine.add(new HighlightCombinatorElement((byte) 1, e));
+ balanceStack.add(e);
+ };
+ };
+
+ // Get all combined elements as a string
+ public String toString () {
+ StringBuilder sb = new StringBuilder();
+ for (HighlightCombinatorElement e : combine) {
+ sb.append(e.toString()).append("\n");
+ };
+ return sb.toString();
+ };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/match/HighlightCombinatorElement.java b/src/main/java/de/ids_mannheim/korap/match/HighlightCombinatorElement.java
new file mode 100644
index 0000000..036e244
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/match/HighlightCombinatorElement.java
@@ -0,0 +1,154 @@
+package de.ids_mannheim.korap.match;
+
+import org.apache.lucene.util.FixedBitSet;
+import de.ids_mannheim.korap.KorapMatch;
+import de.ids_mannheim.korap.match.Relation;
+import static de.ids_mannheim.korap.util.KorapHTML.*;
+import java.util.*;
+import java.io.*;
+
+/*
+ Class for elements with highlighting information
+*/
+public class HighlightCombinatorElement {
+
+ // Type 0: Textual data
+ // Type 1: Opening
+ // Type 2: Closing
+ public byte type;
+
+ public int number = 0;
+
+ public String characters;
+ public boolean terminal = true;
+
+ // Constructor for highlighting elements
+ public HighlightCombinatorElement (byte type, int number) {
+ this.type = type;
+ this.number = number;
+ };
+
+ // Constructor for highlighting elements,
+ // that may not be terminal, i.e. they were closed and will
+ // be reopened for overlapping issues.
+ public HighlightCombinatorElement (byte type, int number, boolean terminal) {
+ this.type = type;
+ this.number = number;
+ this.terminal = terminal;
+ };
+
+ // Constructor for textual data
+ public HighlightCombinatorElement (String characters) {
+ this.type = (byte) 0;
+ this.characters = characters;
+ };
+
+ // Return html fragment for this combinator element
+ public String toHTML (KorapMatch match, FixedBitSet level, byte[] levelCache) {
+ // Opening
+ if (this.type == 1) {
+ StringBuilder sb = new StringBuilder();
+ if (this.number == -1) {
+ sb.append("<span class=\"match\">");
+ }
+
+ else if (this.number < -1) {
+ sb.append("<span xml:id=\"")
+ .append(match.getPosID(
+ match.getClassID(this.number)))
+ .append("\">");
+ }
+
+ else if (this.number >= 256) {
+ sb.append("<span ");
+ if (this.number < 2048) {
+ sb.append("title=\"")
+ .append(match.getAnnotationID(this.number))
+ .append('"');
+ }
+ else {
+ Relation rel = match.getRelationID(this.number);
+ sb.append("xlink:title=\"")
+ .append(rel.annotation)
+ .append("\" xlink:type=\"simple\" xlink:href=\"#")
+ .append(match.getPosID(rel.ref))
+ .append('"');
+ };
+ sb.append('>');
+ }
+ else {
+ // Get the first free level slot
+ byte pos;
+ if (levelCache[this.number] != '\0') {
+ pos = levelCache[this.number];
+ }
+ else {
+ pos = (byte) level.nextSetBit(0);
+ level.clear(pos);
+ levelCache[this.number] = pos;
+ };
+ sb.append("<em class=\"class-")
+ .append(this.number)
+ .append(" level-")
+ .append(pos)
+ .append("\">");
+ };
+ return sb.toString();
+ }
+ // Closing
+ else if (this.type == 2) {
+ if (this.number <= -1 || this.number >= 256)
+ return "</span>";
+
+ if (this.terminal)
+ level.set((int) levelCache[this.number]);
+ return "</em>";
+ };
+
+ // HTML encode primary data
+ return encodeHTML(this.characters);
+ };
+
+ // Return bracket fragment for this combinator element
+ public String toBrackets (KorapMatch match) {
+ if (this.type == 1) {
+ StringBuilder sb = new StringBuilder();
+
+ // Match
+ if (this.number == -1) {
+ sb.append("[");
+ }
+
+ // Identifier
+ else if (this.number < -1) {
+ sb.append("{#");
+ sb.append(match.getClassID(this.number));
+ sb.append(':');
+ }
+
+ // Highlight, Relation, Span
+ else {
+ sb.append("{");
+ if (this.number >= 256) {
+ if (this.number < 2048)
+ sb.append(match.getAnnotationID(this.number));
+ else {
+ Relation rel = match.getRelationID(this.number);
+ sb.append(rel.annotation);
+ sb.append('>').append(rel.ref);
+ };
+ sb.append(':');
+ }
+ else if (this.number != 0)
+ sb.append(this.number).append(':');
+ };
+ return sb.toString();
+ }
+ else if (this.type == 2) {
+ if (this.number == -1)
+ return "]";
+ return "}";
+ };
+ return this.characters;
+ };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/index/MatchIdentifier.java b/src/main/java/de/ids_mannheim/korap/match/MatchIdentifier.java
similarity index 98%
rename from src/main/java/de/ids_mannheim/korap/index/MatchIdentifier.java
rename to src/main/java/de/ids_mannheim/korap/match/MatchIdentifier.java
index 758aaad..1110774 100644
--- a/src/main/java/de/ids_mannheim/korap/index/MatchIdentifier.java
+++ b/src/main/java/de/ids_mannheim/korap/match/MatchIdentifier.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.index;
+package de.ids_mannheim.korap.match;
import java.util.*;
import java.util.regex.*;
import de.ids_mannheim.korap.index.DocIdentifier;
diff --git a/src/main/java/de/ids_mannheim/korap/index/PosIdentifier.java b/src/main/java/de/ids_mannheim/korap/match/PosIdentifier.java
similarity index 94%
rename from src/main/java/de/ids_mannheim/korap/index/PosIdentifier.java
rename to src/main/java/de/ids_mannheim/korap/match/PosIdentifier.java
index f17dd6c..1893a67 100644
--- a/src/main/java/de/ids_mannheim/korap/index/PosIdentifier.java
+++ b/src/main/java/de/ids_mannheim/korap/match/PosIdentifier.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.index;
+package de.ids_mannheim.korap.match;
import java.util.*;
import de.ids_mannheim.korap.index.DocIdentifier;
diff --git a/src/main/java/de/ids_mannheim/korap/match/Relation.java b/src/main/java/de/ids_mannheim/korap/match/Relation.java
new file mode 100644
index 0000000..f8e01c7
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/match/Relation.java
@@ -0,0 +1,13 @@
+package de.ids_mannheim.korap.match;
+
+/**
+ * Class for relational highlights.
+ */
+public class Relation {
+ public int ref;
+ public String annotation;
+ public Relation (String annotation, int ref) {
+ this.annotation = annotation;
+ this.ref = ref;
+ };
+};
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestMatchIdentifier.java b/src/test/java/de/ids_mannheim/korap/index/TestMatchIdentifier.java
index 6d0a303..c0e6b05 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestMatchIdentifier.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestMatchIdentifier.java
@@ -9,8 +9,8 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import de.ids_mannheim.korap.index.MatchIdentifier;
-import de.ids_mannheim.korap.index.PosIdentifier;
+import de.ids_mannheim.korap.match.MatchIdentifier;
+import de.ids_mannheim.korap.match.PosIdentifier;
import de.ids_mannheim.korap.KorapIndex;
import de.ids_mannheim.korap.KorapQuery;