Added a query function for retrieving relationspans with attribute(s)
diff --git a/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java b/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java
index 6bc3370..5f0dd9d 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SimpleSpanQuery.java
@@ -17,7 +17,7 @@
 		implements Cloneable{		
 	
 	protected SpanQuery firstClause, secondClause;
-	protected List<SpanQuery> clauseList;
+	protected List<SpanQuery> clauseList=null;
 	private String field;
 	protected boolean collectPayloads;
     	
diff --git a/src/main/java/de/ids_mannheim/korap/query/SpanElementAttributeQuery.java b/src/main/java/de/ids_mannheim/korap/query/SpanElementAttributeQuery.java
index 1c30699..a825ec3 100644
--- a/src/main/java/de/ids_mannheim/korap/query/SpanElementAttributeQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/query/SpanElementAttributeQuery.java
@@ -62,7 +62,7 @@
 	@Override
 	public Spans getSpans(AtomicReaderContext context, Bits acceptDocs,
 			Map<Term, TermContext> termContexts) throws IOException {
-		return new ElementAttributeSpans(this, context, acceptDocs, termContexts);
+		return null; //new ElementAttributeSpans(this, context, acceptDocs, termContexts);
 	}
 
 	@Override
diff --git a/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java b/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java
new file mode 100644
index 0000000..7352efc
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/SpanWithAttributeQuery.java
@@ -0,0 +1,139 @@
+package de.ids_mannheim.korap.query;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.lucene.index.AtomicReaderContext;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermContext;
+import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.Spans;
+import org.apache.lucene.util.Bits;
+
+import de.ids_mannheim.korap.query.spans.ElementAttributeSpans;
+import de.ids_mannheim.korap.query.spans.ElementSpans;
+import de.ids_mannheim.korap.query.spans.RelationSpans;
+
+/**	Enumeration of spans (e.g. element or relation spans) having some specific attribute(s) or 
+ * 	<em>not</em> having some attribute(s).
+ * 
+ * 	@author margaretha
+ */
+public class SpanWithAttributeQuery extends SimpleSpanQuery{
+		
+	private boolean isMultipleAttributes;
+	private String type;
+	
+	public SpanWithAttributeQuery(SpanElementQuery firstClause,
+			SpanAttributeQuery secondClause, boolean collectPayloads) {
+		super(firstClause, secondClause, collectPayloads);
+		type = "spanElementWithAttribute"; 
+	}
+	
+	public SpanWithAttributeQuery(SpanElementQuery firstClause,
+			List<SpanQuery> secondClauses, boolean collectPayloads) {
+		super(firstClause, secondClauses, collectPayloads);
+		isMultipleAttributes = true;
+		type = "spanElementWithAttribute";
+	}
+	
+	public SpanWithAttributeQuery(SpanRelationQuery firstClause,
+			SpanAttributeQuery secondClause, boolean collectPayloads) {
+		super(firstClause, secondClause, collectPayloads);
+		type = "spanRelationWithAttribute";		
+	}
+	
+	public SpanWithAttributeQuery(SpanRelationQuery firstClause,
+			List<SpanQuery> secondClauses, boolean collectPayloads) {
+		super(firstClause, secondClauses, collectPayloads);
+		isMultipleAttributes = true;
+		type = "spanRelationWithAttribute";		
+	}
+
+	@Override
+	public SimpleSpanQuery clone() {
+		SpanWithAttributeQuery sq;
+		if (!isMultipleAttributes){			
+			if (type.equals("spanElementWithAttribute")){			
+				sq = new SpanWithAttributeQuery( 
+						(SpanElementQuery) firstClause.clone(), 
+						(SpanAttributeQuery) secondClause.clone(), 
+						collectPayloads);
+			}
+			else {
+				sq = new SpanWithAttributeQuery( 
+						(SpanRelationQuery) firstClause.clone(), 
+						(SpanAttributeQuery) secondClause.clone(), 
+						collectPayloads);
+			}
+		}
+		else {
+			List<SpanQuery> clauseList = new ArrayList<SpanQuery>();
+			SpanAttributeQuery saq;
+			for (SpanQuery q : this.clauseList ){
+				saq = (SpanAttributeQuery) q;
+				clauseList.add(saq.clone());
+			}
+			
+			if (type.equals("spanElementWithAttribute")){			
+				sq = new SpanWithAttributeQuery( 
+						(SpanElementQuery) firstClause.clone(), 
+						clauseList, 
+						collectPayloads);
+			}
+			else {
+				sq = new SpanWithAttributeQuery( 
+						(SpanRelationQuery) firstClause.clone(), 
+						clauseList, 
+						collectPayloads);
+			}
+		}
+		return sq;
+	}
+
+	@Override
+	public Spans getSpans(AtomicReaderContext context, Bits acceptDocs,
+			Map<Term, TermContext> termContexts) throws IOException {
+		
+		Spans spans = this.getFirstClause().getSpans(context, acceptDocs, termContexts);
+		
+		if (type.equals("spanElementWithAttribute")){			
+			return new ElementAttributeSpans(this, (ElementSpans) spans, 
+					context, acceptDocs, termContexts);
+		}
+		
+		return new ElementAttributeSpans(this, (RelationSpans) spans,
+				context, acceptDocs, termContexts);
+	}
+
+	@Override
+	public String toString(String field) {
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append(type);
+		sb.append("(");
+		sb.append(firstClause.toString(field));
+		sb.append(", ");
+		if (isMultipleAttributes){
+			sb.append("[");
+			
+			SpanQuery sq;
+			for (int i=0; i < clauseList.size(); i++){
+				sq = clauseList.get(i); 
+				sb.append(sq.toString(field));
+				
+				if (i < clauseList.size() -1)
+					sb.append(", ");
+			}
+			
+			sb.append("]");
+		}
+		else {
+			sb.append(secondClause.toString(field));
+		}
+		sb.append(")");
+		return sb.toString();
+	}
+}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java
index 66b16f3..13fa867 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/AttributeSpans.java
@@ -33,7 +33,7 @@
 	
 	private List<CandidateAttributeSpan> candidateList;
 	private int currentDoc, currentPosition;
-	private short elementRef;
+	private short spanId;
 	private boolean isFinish;
 	
 	protected Logger logger = LoggerFactory.getLogger(AttributeSpans.class);
@@ -71,7 +71,7 @@
 				this.matchDocNumber = cs.getDoc();
 				this.matchStartPosition = cs.getStart();
 				this.matchEndPosition = cs.getEnd();
-				this.setElementRef(cs.getElementRef());
+				this.setSpanId(cs.getSpanId());
 				candidateList.remove(0);
 				return true;
 			}
@@ -98,10 +98,9 @@
 		while (hasMoreSpans &&	firstSpans.doc() == currentDoc && 
 				firstSpans.start() == currentPosition){
 			
-			short elementRef = retrieveElementRef(firstSpans); 
-			if (DEBUG)
-                            logger.info("ElementRef: "+elementRef);
-			candidateList.add(new CandidateAttributeSpan(firstSpans,elementRef));
+			short spanId = retrieveSpanId(firstSpans);			
+            //logger.info("ElementRef: "+elementRef);
+			candidateList.add(new CandidateAttributeSpan(firstSpans,spanId));
 			hasMoreSpans = firstSpans.next();
 		}
 		
@@ -111,7 +110,7 @@
 	
 	/**	Get the elementRef from payload
 	 * */
-	private short retrieveElementRef(Spans firstSpans) throws IOException {		
+	private short retrieveSpanId(Spans firstSpans) throws IOException {		
 		List<byte[]> payload = (List<byte[]>) firstSpans.getPayload();
 		long s = System.nanoTime();
 		ByteBuffer wrapper = ByteBuffer.wrap(payload.get(0));
@@ -122,12 +121,12 @@
 		return num;				
 	}
 	
-	public short getElementRef(){
-		return this.elementRef;
+	public short getSpanId(){
+		return this.spanId;
 	}
 
-	public void setElementRef(short elementRef) {
-		this.elementRef = elementRef;
+	public void setSpanId(short spanId) {
+		this.spanId = spanId;
 	}
 
 	public boolean isFinish() {
@@ -162,27 +161,27 @@
 	class CandidateAttributeSpan extends CandidateSpan 
 			implements Comparable<CandidateSpan>{
 
-		private short elementRef;
+		private short spanId;
 		
-		public CandidateAttributeSpan(Spans span, short elementRef) 
+		public CandidateAttributeSpan(Spans span, short spanId) 
 				throws IOException {
 			super(span);
-			setElementRef(elementRef);
+			setSpanId(spanId);
 		}
 		
-		public void setElementRef(short elementRef) {
-			this.elementRef = elementRef;
+		public void setSpanId(short spanId) {
+			this.spanId = spanId;
 		}
-		public short getElementRef() {
-			return elementRef;
+		public short getSpanId() {
+			return spanId;
 		}
 
 		@Override
 		public int compareTo(CandidateSpan o) {
 			CandidateAttributeSpan cs = (CandidateAttributeSpan) o;
-			if (this.elementRef == cs.elementRef)
+			if (this.spanId == cs.spanId)
 				return 0;
-			else if (this.elementRef > cs.elementRef )
+			else if (this.spanId > cs.spanId )
 				return 1;
 			return -1;			
 		}		
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java b/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java
index 269fc5d..48fdd90 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/CandidateSpan.java
@@ -107,11 +107,11 @@
 		this.childSpan = childSpan;
 	}
 
-	public short getElementRef() {
+	public short getSpanId() {
 		return elementRef;
 	}
 
-	public void setElementRef(short elementRef) {
+	public void setSpanId(short elementRef) {
 		this.elementRef = elementRef;
 	}
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/ElementAttributeSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/ElementAttributeSpans.java
index a378e1a..31fc6c7 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/ElementAttributeSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/ElementAttributeSpans.java
@@ -14,7 +14,7 @@
 import org.slf4j.LoggerFactory;
 
 import de.ids_mannheim.korap.query.SpanAttributeQuery;
-import de.ids_mannheim.korap.query.SpanElementAttributeQuery;
+import de.ids_mannheim.korap.query.SpanWithAttributeQuery;
 
 /** Span enumeration of elements that have some attribute and/or do <em>not</em> 
  * 	have some attributes. This class handles <em>and</em> operation on attributes.
@@ -27,7 +27,7 @@
  * */
 public class ElementAttributeSpans extends SimpleSpans{
 	
-	private ElementSpans elements;
+	private WithIdSpans withAttributeSpans;
 	private List<AttributeSpans> attributeList;
 	private List<AttributeSpans> notAttributeList;
 	
@@ -36,30 +36,41 @@
         // This advices the java compiler to ignore all loggings
         public static final boolean DEBUG = false;	
 
-	public ElementAttributeSpans(SpanElementAttributeQuery simpleSpanQuery,
+	public ElementAttributeSpans(SpanWithAttributeQuery spanWithAttributeQuery,
+			WithIdSpans withIdSpans,
 			AtomicReaderContext context, Bits acceptDocs,
 			Map<Term, TermContext> termContexts) throws IOException {
-		super(simpleSpanQuery, context, acceptDocs, termContexts);		
-		elements = (ElementSpans) firstSpans;
-		elements.isElementRef = true; // dummy setting enabling reading elementRef
-		hasMoreSpans = elements.next();
+		super(spanWithAttributeQuery, context, acceptDocs, termContexts);		
+		withAttributeSpans = withIdSpans;
+		withAttributeSpans.hasSpanId = true; // dummy setting enabling reading elementRef
+		hasMoreSpans = withAttributeSpans.next();
 		
 		attributeList = new ArrayList<AttributeSpans>();
-		notAttributeList = new ArrayList<AttributeSpans>();
+		notAttributeList = new ArrayList<AttributeSpans>();		
 		
-		List<SpanQuery> sqs = simpleSpanQuery.getClauseList();
-		AttributeSpans as;
-		for (SpanQuery sq: sqs){
-			as = (AttributeSpans) sq.getSpans(context, acceptDocs, termContexts);
-			if (((SpanAttributeQuery) sq).isNegation()){
-				notAttributeList.add(as);
-				as.next();
+		List<SpanQuery> sqs = spanWithAttributeQuery.getClauseList();
+		if (sqs != null){
+			for (SpanQuery sq: sqs){
+				addAttributes(sq, context, acceptDocs, termContexts);
 			}
-			else {
-				attributeList.add(as);
-				hasMoreSpans &= as.next();
-			}
-		}		
+		}
+		else {
+			addAttributes(spanWithAttributeQuery.getSecondClause(), 
+					context, acceptDocs, termContexts);
+		}
+	}
+	
+	private void addAttributes(SpanQuery sq, AtomicReaderContext context, Bits acceptDocs,
+			Map<Term, TermContext> termContexts) throws IOException {
+		AttributeSpans as = (AttributeSpans) sq.getSpans(context, acceptDocs, termContexts);
+		if (((SpanAttributeQuery) sq).isNegation()){
+			notAttributeList.add(as);
+			as.next();
+		}
+		else {
+			attributeList.add(as);
+			hasMoreSpans &= as.next();
+		}	
 	}
 
 	@Override
@@ -76,20 +87,19 @@
 	private boolean advance() throws IOException {
 		
 		while (hasMoreSpans && computeElementPosition()){			
-		        if (DEBUG)
-		 	    logger.info("element: " + elements.start() + ","+ elements.end() +
-					" ref:"+elements.getElementRef());
+		 	    logger.info("element: " + withAttributeSpans.start() + ","+ withAttributeSpans.end() +
+					" ref:"+withAttributeSpans.getSpanId());
 			
 			if (checkElementRef() && checkNotElementRef()){			
-				this.matchDocNumber = elements.doc();
-				this.matchStartPosition = elements.start();
-				this.matchEndPosition = elements.end();
-				this.matchPayload = elements.getPayload();
+				this.matchDocNumber = withAttributeSpans.doc();
+				this.matchStartPosition = withAttributeSpans.start();
+				this.matchEndPosition = withAttributeSpans.end();
+				this.matchPayload = withAttributeSpans.getPayload();
 				hasMoreSpans = attributeList.get(0).next();
-				if (DEBUG)
-				    logger.info("MATCH "+matchDocNumber);
 				
-				hasMoreSpans = elements.next();		
+			    logger.info("MATCH "+matchDocNumber);
+				
+				hasMoreSpans = withAttributeSpans.next();		
 				return true;
 			}
 		}
@@ -102,13 +112,13 @@
 	private boolean checkElementRef() throws IOException{
 		
 		for (AttributeSpans attribute: attributeList){			
-			if (elements.getElementRef() != attribute.getElementRef()){
+			if (withAttributeSpans.getSpanId() != attribute.getSpanId()){
 			        if (DEBUG)
 				    logger.info("attribute ref doesn't match");
-				if (elements.getElementRef() < attribute.getElementRef())
+				if (withAttributeSpans.getSpanId() < attribute.getSpanId())
 					hasMoreSpans = attribute.next();
 				else {
-					hasMoreSpans = elements.next();				
+					hasMoreSpans = withAttributeSpans.next();				
 				}
 				
 				return false;
@@ -123,11 +133,11 @@
 	private boolean checkNotElementRef() throws IOException{
 		for (AttributeSpans notAttribute: notAttributeList){
 			if (!notAttribute.isFinish() && 
-					elements.start() == notAttribute.start() &&
-					elements.getElementRef() == notAttribute.getElementRef()){
+					withAttributeSpans.start() == notAttribute.start() &&
+					withAttributeSpans.getSpanId() == notAttribute.getSpanId()){
 			        if (DEBUG)
 				    logger.info("not attribute ref exists");
-				hasMoreSpans = elements.next();	
+				hasMoreSpans = withAttributeSpans.next();	
 				return false;
 			}
 		}
@@ -141,9 +151,9 @@
 
 		while (hasMoreSpans){
 			
-			if (elements.getElementRef() < 1){ // the element does not have an attribute
-				elements.isElementRef = true; // dummy setting enabling reading elementRef
-				hasMoreSpans = elements.next();
+			if (withAttributeSpans.getSpanId() < 1){ // the element does not have an attribute
+				withAttributeSpans.hasSpanId = true; // dummy setting enabling reading elementRef
+				hasMoreSpans = withAttributeSpans.next();
 				if (DEBUG)
 				    logger.info("skip");
 				continue;
@@ -152,7 +162,7 @@
 			if (checkAttributeListPosition() && 
 					checkNotAttributeListPosition()){
 			        if (DEBUG)
-				    logger.info("element is found: "+ elements.start());
+				    logger.info("element is found: "+ withAttributeSpans.start());
 				return true;
 			}			
 		}		
@@ -171,10 +181,10 @@
 			// advance the doc# of not AttributeSpans
 		        if (DEBUG)
 			    logger.info("a "+a.start());
-			while (!a.isFinish() &&	 a.doc() <= elements.doc()){
+			while (!a.isFinish() &&	 a.doc() <= withAttributeSpans.doc()){
 				
-				if (a.doc() == elements.doc() &&
-						a.start() >= elements.start())
+				if (a.doc() == withAttributeSpans.doc() &&
+						a.start() >= withAttributeSpans.start())
 					break;
 				
 				if (!a.next()) a.setFinish(true);
@@ -188,40 +198,40 @@
 	 * 	as the element.
 	 * */
 	private boolean checkAttributeListPosition() throws IOException{
-		int currentPosition = elements.start();
+		int currentPosition = withAttributeSpans.start();
 		boolean isSame = true;
 		boolean isFirst = true;
 		
 		for (AttributeSpans a : attributeList){
-			if(!ensureSamePosition(elements, a)) return false;
+			if(!ensureSamePosition(withAttributeSpans, a)) return false;
 			        if (DEBUG)
-				    logger.info("pos:" + elements.start());
+				    logger.info("pos:" + withAttributeSpans.start());
 				if (isFirst){ 
 					isFirst = false;
-					currentPosition = elements.start();
+					currentPosition = withAttributeSpans.start();
 				}
-				else if (currentPosition != elements.start()){					
-					currentPosition = elements.start();
+				else if (currentPosition != withAttributeSpans.start()){					
+					currentPosition = withAttributeSpans.start();
 					isSame = false;
 				
 			}				 
 		}
 		if (DEBUG)
-		    logger.info("same pos: "+isSame+ ", pos "+elements.start());
+		    logger.info("same pos: "+isSame+ ", pos "+withAttributeSpans.start());
 		return isSame;
 	}
 	
 	/** Advance the element or attribute spans to be in the same doc 
 	 * 	and start position.
 	 * */
-	private boolean ensureSamePosition(ElementSpans elements,
+	private boolean ensureSamePosition(WithIdSpans spans,
 			AttributeSpans attributes) throws IOException {
 		
-		while (hasMoreSpans && ensureSameDoc(elements, attributes)){
-			if (attributes.start() == elements.start())
+		while (hasMoreSpans && ensureSameDoc(spans, attributes)){
+			if (attributes.start() == spans.start())
 				return true;
-			else if (attributes.start() > elements.start()) 
-				hasMoreSpans = elements.next();
+			else if (attributes.start() > spans.start()) 
+				hasMoreSpans = spans.next();
 			else 
 				hasMoreSpans= attributes.next();
 		}
@@ -231,8 +241,8 @@
 
 	@Override
 	public boolean skipTo(int target) throws IOException {
-		if (hasMoreSpans && (elements.doc() < target)){
-  			if (!elements.skipTo(target)){
+		if (hasMoreSpans && (withAttributeSpans.doc() < target)){
+  			if (!withAttributeSpans.skipTo(target)){
   				return false;
   			}
   		}		
@@ -250,7 +260,7 @@
 		for (AttributeSpans as: notAttributeList){
 			cost += as.cost();
 		}
-		return elements.cost() + cost;
+		return withAttributeSpans.cost() + cost;
 	}
 
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/ElementSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/ElementSpans.java
index 31bc8a9..45774b9 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/ElementSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/ElementSpans.java
@@ -24,14 +24,12 @@
  *
  * Use copyFrom instead of clone
  */
-public class ElementSpans extends SimpleSpans {
+public class ElementSpans extends WithIdSpans {
 
 	private List<CandidateElementSpans> candidateList;
 	private int currentDoc, currentPosition;
-	private short elementRef;
-	private TermSpans termSpans;
-	
-	public boolean isElementRef = false; // A dummy flag
+	//private short elementRef;
+	private TermSpans termSpans;	
 	
 	protected Logger logger = LoggerFactory.getLogger(ElementSpans.class);
 
@@ -68,7 +66,8 @@
 				this.matchStartPosition = cs.getStart();
 				this.matchEndPosition = cs.getEnd();
 				this.matchPayload = cs.getPayloads();				
-				this.setElementRef(cs.getElementRef());				
+				//this.setElementRef(cs.getSpanId());				
+				this.setSpanId(cs.getSpanId());
 				candidateList.remove(0);
 				return true;
 			}
@@ -90,7 +89,8 @@
 		while (hasMoreSpans &&	termSpans.doc() == currentDoc && 
 				termSpans.start() == currentPosition){
 			CandidateElementSpans cs = new CandidateElementSpans(termSpans,
-					elementRef);
+					spanId);
+					//elementRef);
 			readPayload(cs);
 			candidateList.add(cs);
 			hasMoreSpans = termSpans.next();
@@ -120,15 +120,15 @@
 			
 			cs.setEnd(PayloadReader.readInteger(payload,8));
 			
-			if (isElementRef ){
+			if (hasSpanId){
 				// Copy rest of payloads after the end position and elementref
 				//payloadBuffer.put(payload.bytes, payload.offset + 14, payload.length - 14);				
-				cs.setElementRef(PayloadReader.readShort(payload,12));
+				cs.setSpanId(PayloadReader.readShort(payload,12));
 			}
 			else{
 				// Copy rest of payloads after the end position
 				//payloadBuffer.put(payload.bytes, payload.offset + 12, payload.length - 12);
-				cs.setElementRef((short) -1);
+				cs.setSpanId((short) -1);
 			}
 			
 			//byte[] offsetCharacters = new byte[8];
@@ -138,7 +138,7 @@
 	    }
 	    else {	
 			cs.setEnd(cs.getStart());
-			cs.setElementRef((short) -1);
+			cs.setSpanId((short) -1);
 			cs.setPayloads(null);
     	}
 	}
@@ -162,13 +162,13 @@
 		return termSpans.cost();
 	}
 	
-	public short getElementRef() {
-		return elementRef;
-	}
-
-	public void setElementRef(short elementRef) {
-		this.elementRef = elementRef;
-	}
+//	public short getElementRef() {
+//		return elementRef;
+//	}
+//
+//	public void setElementRef(short elementRef) {
+//		this.elementRef = elementRef;
+//	}
 	
 	/** Match candidate for element spans.
 	 * */	
@@ -179,13 +179,13 @@
 		public CandidateElementSpans(Spans span, short elementRef) 
 				throws IOException {
 			super(span);
-			setElementRef(elementRef);
+			setSpanId(elementRef);
 		}
 		
-		public void setElementRef(short elementRef) {
+		public void setSpanId(short elementRef) {
 			this.elementRef = elementRef;
 		}
-		public short getElementRef() {
+		public short getSpanId() {
 			return elementRef;
 		}	
 	}
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java
index 0b0a901..375c840 100644
--- a/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/RelationSpans.java
@@ -38,9 +38,9 @@
  * 
  * 	@author margaretha
  * */
-public class RelationSpans extends SimpleSpans{
+public class RelationSpans extends WithIdSpans{
 
-	short relationId;
+	//short relationId;
 	int targetStart, targetEnd;
 	int currentDoc, currentPosition;
 	
@@ -71,7 +71,8 @@
 				this.matchDocNumber = cs.getDoc();
 				this.matchStartPosition = cs.getStart();
 				this.matchEndPosition = cs.getEnd();
-				this.matchPayload = cs.getPayloads();				
+				this.matchPayload = cs.getPayloads();	
+				this.spanId = cs.getSpanId(); // relation id
 				candidateList.remove(0);
 				return true;
 			}
@@ -96,7 +97,7 @@
 		Collections.sort(candidateList);
 		
 		/*for (CandidateRelationSpan cs:candidateList){
-		System.out.println(cs.getStart()+","+cs.getEnd() //+" <size:" +payload.get(0).length 
+			System.out.println(cs.getStart()+","+cs.getEnd() //+" <size:" +payload.get(0).length 
 				+" target "+cs.getTargetStart()+","+cs.getTargetEnd() +" id:"+cs.getRelationId());
 		}*/
 	}
@@ -112,7 +113,7 @@
 			case 6: // Token to token
 				i = PayloadReader.readInteger(payloadBytesRef,0);
 				cs.setTargetStart(i);
-				cs.setTargetEnd(i+1);
+				cs.setTargetEnd(i);
 				break;
 	
 			case 10: // Token to span
@@ -124,7 +125,7 @@
 				cs.setEnd(PayloadReader.readInteger(payloadBytesRef,0));
 				i = PayloadReader.readInteger(payloadBytesRef,5);
 				cs.setTargetStart(i);
-				cs.setTargetEnd(i+1);
+				cs.setTargetEnd(i);
 				break;
 			
 			case 14: // Span to span
@@ -134,7 +135,7 @@
 				break;
 		}
 		
-		cs.setRelationId(PayloadReader.readShort(payloadBytesRef, length-2));
+		cs.setSpanId(PayloadReader.readShort(payloadBytesRef, length-2)); //relation id
 	}
 
 	@Override
@@ -155,14 +156,14 @@
 	public long cost() {
 		return firstSpans.cost();
 	}
-
+/*
 	public short getRelationId() {
 		return relationId;
 	}
 
 	public void setRelationId(short relationId) {
 		this.relationId = relationId;
-	}
+	}*/
 
 	public int getTargetStart() {
 		return targetStart;
@@ -183,7 +184,7 @@
 	
 	class CandidateRelationSpan extends CandidateSpan implements Comparable<CandidateSpan>{
 		
-		private int targetStart, targetEnd, relationId;
+		private int targetStart, targetEnd;
 		
 		public CandidateRelationSpan(Spans span) throws IOException{
 			super(span);
@@ -226,14 +227,6 @@
 		public void setTargetStart(int targetStart) {
 			this.targetStart = targetStart;
 		}
-
-		public int getRelationId() {
-			return relationId;
-		}
-
-		public void setRelationId(int relationId) {
-			this.relationId = relationId;
-		}
 	}
 	
 }
diff --git a/src/main/java/de/ids_mannheim/korap/query/spans/WithIdSpans.java b/src/main/java/de/ids_mannheim/korap/query/spans/WithIdSpans.java
new file mode 100644
index 0000000..76ee1cc
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/query/spans/WithIdSpans.java
@@ -0,0 +1,40 @@
+package de.ids_mannheim.korap.query.spans;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.AtomicReaderContext;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermContext;
+import org.apache.lucene.util.Bits;
+
+import de.ids_mannheim.korap.query.SpanElementQuery;
+import de.ids_mannheim.korap.query.SpanRelationQuery;
+
+public abstract class WithIdSpans extends SimpleSpans{
+
+	protected short spanId;
+	protected boolean hasSpanId = false; // A dummy flag
+	
+	public WithIdSpans(SpanElementQuery spanElementQuery,
+			AtomicReaderContext context, Bits acceptDocs,
+			Map<Term, TermContext> termContexts) throws IOException {
+		super(spanElementQuery, context, acceptDocs, termContexts);
+	}
+	
+	public WithIdSpans(SpanRelationQuery spanRelationQuery,
+			AtomicReaderContext context, Bits acceptDocs,
+			Map<Term, TermContext> termContexts) throws IOException {
+		super(spanRelationQuery, context, acceptDocs, termContexts);
+	}
+
+	public short getSpanId() {
+		return spanId;
+	}
+
+	public void setSpanId(short spanId) {
+		this.spanId = spanId;
+	}
+		
+	
+}
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java
index 5749746..88e5c3f 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestAttributeIndex.java
@@ -14,9 +14,9 @@
 import de.ids_mannheim.korap.KorapIndex;
 import de.ids_mannheim.korap.KorapResult;
 import de.ids_mannheim.korap.query.SpanAttributeQuery;
-import de.ids_mannheim.korap.query.SpanElementAttributeQuery;
 import de.ids_mannheim.korap.query.SpanElementQuery;
 import de.ids_mannheim.korap.query.SpanNextQuery;
+import de.ids_mannheim.korap.query.SpanWithAttributeQuery;
 
 public class TestAttributeIndex {
 	
@@ -92,7 +92,7 @@
 		List<SpanQuery> sql = new ArrayList<>();
 		sql.add(saq);
 		
-		SpanQuery sq = new SpanElementAttributeQuery(
+		SpanQuery sq = new SpanWithAttributeQuery(
 				new SpanElementQuery("base", "div"),
 				sql, true);
 		
@@ -125,7 +125,7 @@
 				new SpanTermQuery(new Term("base","@:class=title")),true)
 		);
 		
-		SpanQuery sq = new SpanElementAttributeQuery(
+		SpanQuery sq = new SpanWithAttributeQuery(
 				new SpanElementQuery("base", "div"),
 				sql, true);
 		
@@ -146,7 +146,7 @@
 				new SpanTermQuery(new Term("base","@:class=book")),true,true)
 		);
 		
-		sq = new SpanElementAttributeQuery(
+		sq = new SpanWithAttributeQuery(
 				new SpanElementQuery("base", "div"),
 				sql, true);
 		
@@ -164,7 +164,7 @@
 				new SpanTermQuery(new Term("base","@:class=title")),true,true)
 		);
 		
-		sq = new SpanElementAttributeQuery(
+		sq = new SpanWithAttributeQuery(
 				new SpanElementQuery("base", "div"),
 				sql, true);
 		
@@ -188,7 +188,7 @@
 		sql.add(new SpanAttributeQuery(
 				new SpanTermQuery(new Term("base","@:class=book")),true,true)
 		);
-		SpanQuery sq = new SpanElementAttributeQuery(
+		SpanQuery sq = new SpanWithAttributeQuery(
 				new SpanElementQuery("base", "div"),
 				sql, true);
 		
@@ -218,7 +218,7 @@
 		List<SpanQuery> sql = new ArrayList<>();
 		sql.add(saq);
 		
-		SpanElementAttributeQuery sq = new SpanElementAttributeQuery(
+		SpanWithAttributeQuery sq = new SpanWithAttributeQuery(
 				new SpanElementQuery("base", "div"),
 				sql, true);
 		
diff --git a/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java b/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java
index cb7be66..e155b1e 100644
--- a/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java
+++ b/src/test/java/de/ids_mannheim/korap/index/TestRelationIndex.java
@@ -9,8 +9,11 @@
 import org.junit.Test;
 
 import de.ids_mannheim.korap.KorapIndex;
+import de.ids_mannheim.korap.KorapMatch;
 import de.ids_mannheim.korap.KorapResult;
+import de.ids_mannheim.korap.query.SpanAttributeQuery;
 import de.ids_mannheim.korap.query.SpanRelationQuery;
+import de.ids_mannheim.korap.query.SpanWithAttributeQuery;
 
     /*
 
@@ -83,20 +86,64 @@
         fd.addTV("base",
             "text",             
             "[(0-1)s:c|_1#0-1|>:xip/syntax-dep_rel$<i>3<i>6<i>9<s>2|>:xip/syntax-dep_rel$<i>6<i>9<s>1]" +
+            		"r@:func=subj$<s>2]" +
             "[(1-2)s:e|_2#1-2]" +             
             "[(2-3)s:c|_3#2-3]" +
             "[(3-4)s:c|s:b|_4#3-4]" + 
             "[(4-5)s:e|s:d|_5#4-5]" +
             "[(5-6)s:c|_6#5-6]" +
             "[(6-7)s:d|_7#6-7|<:xip/syntax-dep_rel$<i>9<b>0<i>0<s>1|>:xip/syntax-dep_rel$<i>9<b>0<i>9<s>3|" +
-            	"<:xip/syntax-dep_rel$<i>9<i>1<i>3<s>2]" +
+            	"<:xip/syntax-dep_rel$<i>9<i>1<i>3<s>2|" +
+            	"r@:func=obj$<s>2]" +
             "[(7-8)s:e|_8#7-8]" + 
             "[(8-9)s:e|s:b|_9#8-9]" + 
             "[(9-10)s:d|_10#9-10|<:xip/syntax-dep_rel$<i>6<i>9<s>2]");
         return fd;
     }
 	
+	private FieldDocument createFieldDoc2(){
+    	FieldDocument fd = new FieldDocument();
+        fd.addString("ID", "doc-2");
+        fd.addTV("base",
+            "Ich kaufe die Blümen für meine Mutter.",             
+            "[(0-3)s:Ich|_0#0-3|pos:NN|<>:s#0-38$<i>7<s>-1|<>:np#0-3$<i>1<s>-1|" +
+            	">:child-of$<i>0<i>7<s>1|" +            		
+            	"<:dep$<i>1<s>2|" +
+            	"r@:func=sbj$<s>1]" +
+            	
+            "[(1-2)s:kaufe|_1#4-9|pos:V|<>:vp#4-38$<i>7<s>-1|" +
+            	">:child-of$<i>7<i>0<i>7<s>1|>:child-of$<i>1<i>7<s>2|" +
+            	">:dep$<i>0<s>3|>:dep$<i>3<s>4]" +
+            	
+            "[(2-3)s:die|_2#10-13|pos:ART|<>:np#10-20$<i>4<s>-1|<>:np#10-38$<i>7<s>-1|" +
+            	">:child-of$<i>4<i>2<i>7<s>1|>:child-of$<i>2<i>4<s>2|>:child-of$<i>7<i>1<i>7<s>2|" +
+            	"<:dep$<i>3<s>3|r@:func=obj$<s>1" +
+            	"]" +
+            
+            "[(3-4)s:Blümen|_3#14-20|pos:NN|" +
+            	">:child-of$<i>2<i>4<s>1|" +
+            	"<:dep$<i>1<s>2|>:dep$<i>2<s>3|>:dep$<i>4<s>4|" +
+            	"r@:func=head$<s>2]" +
+            	
+            "[(4-5)s:für|_4#21-24|pos:PREP|<>:pp#21-38$<i>7<s>-1|" +
+            	">:child-of$<i>4<i>7<s>1|>:child-of$<i>7<i>2<i>7<s>2|" +
+            	"<:dep$<i>3<s>1|>:dep$<i>5<s>2" +
+            	"]" +
+            
+            "[(5-6)s:meine|_5#25-30|pos:ART|<>:np#25-38$<i>7<s>-1|" +
+            	">:child-of$<i>5<i>7<s>1|>:child-of$<i>7<i>4<i>7<s>2|" +
+            	"<:dep$<i>7<s>3" +
+            	"]" +
+            "[(6-7)s:Mutter.|_6#31-38|pos:NN|" +
+            	">:child-of$<i>5<i>7<s>1|" +
+            	">:dep$<i>5<s>2|<:dep$<i>4<s>3|" +
+            	"r@:func=head$<s>3]");
+        
+        return fd;
+    }
 	
+	/** Relations: token to token, token to span, span to span
+	 * */
 	@Test
 	public void testCase1() throws IOException {
 		ki.addDoc(createFieldDoc0());
@@ -134,6 +181,8 @@
 		
 	}
 	
+	/** Relation span to token
+	 * */
 	@Test
 	public void testCase2() throws IOException {
 		ki.addDoc(createFieldDoc0());
@@ -166,4 +215,77 @@
 		assertEquals(9,kr.getMatch(6).getStartPos());
 		assertEquals(10,kr.getMatch(6).getEndPos());
 	}
+	
+	/** Relations with attributes
+	 * */
+	@Test
+	public void testCase3() throws IOException {
+		ki.addDoc(createFieldDoc2());
+		ki.commit();
+		
+		// child-of relations
+		SpanRelationQuery srq = new SpanRelationQuery(
+				new SpanTermQuery(new Term("base",">:child-of")),true);
+		kr = ki.search(srq,(short) 20);
+		
+		assertEquals(12, kr.getTotalResults());
+		
+		// child-of with attr func=sbj
+		SpanWithAttributeQuery wq = 
+			new SpanWithAttributeQuery(srq, 
+				new SpanAttributeQuery( 
+					new SpanTermQuery(new Term("base", "r@:func=sbj")),
+					true), 
+				true
+		);
+		
+		kr = ki.search(wq,(short) 10);		
+		assertEquals(1, kr.getTotalResults());
+		assertEquals(0,kr.getMatch(0).getStartPos()); // token
+		assertEquals(1,kr.getMatch(0).getEndPos());
+		
+		// child-of with attr func-obj
+		wq = new SpanWithAttributeQuery(srq, 
+				new SpanAttributeQuery( 
+					new SpanTermQuery( new Term("base", "r@:func=obj")),
+					true), 
+				true
+		);
+		
+		kr = ki.search(wq,(short) 10);
+		
+		assertEquals(1, kr.getTotalResults());
+		assertEquals(2,kr.getMatch(0).getStartPos()); // element
+		assertEquals(4,kr.getMatch(0).getEndPos());
+			
+		// target of a dependency relation		
+		srq = new SpanRelationQuery(
+				new SpanTermQuery(new Term("base","<:dep")),true);
+		kr = ki.search(srq,(short) 10);
+		
+		assertEquals(6, kr.getTotalResults());
+		
+		// target of a dependency relation, which is also a head
+		wq = new SpanWithAttributeQuery(srq, 
+					new SpanAttributeQuery( 
+						new SpanTermQuery( new Term("base", "r@:func=head")),
+						true), 
+					true
+			);
+		
+		kr = ki.search(wq,(short) 20);
+		
+		assertEquals(2, kr.getTotalResults());
+		assertEquals(3,kr.getMatch(0).getStartPos());
+		assertEquals(4,kr.getMatch(0).getEndPos());
+		assertEquals(6,kr.getMatch(1).getStartPos());
+		assertEquals(7,kr.getMatch(1).getEndPos());
+		
+		/*for (KorapMatch km : kr.getMatches()){		
+			System.out.println(km.getStartPos() +","+km.getEndPos()+" "
+    			+km.getSnippetBrackets());
+		}	*/	
+	}
+	
+	
 }