You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by sf...@apache.org on 2010/12/12 16:13:37 UTC

svn commit: r1044832 [10/14] - in /incubator/stanbol/trunk/rick: indexing/dbPedia/src/main/java/eu/iksproject/rick/indexing/dbPedia/cli/ indexing/genericRdf/src/main/java/eu/iksproject/rick/indexing/rdf/ indexing/geonames/src/main/java/eu/iksproject/ri...

Modified: incubator/stanbol/trunk/rick/yard/solr/src/main/java/eu/iksproject/rick/yard/solr/impl/SolrQueryFactory.java
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/rick/yard/solr/src/main/java/eu/iksproject/rick/yard/solr/impl/SolrQueryFactory.java?rev=1044832&r1=1044831&r2=1044832&view=diff
==============================================================================
--- incubator/stanbol/trunk/rick/yard/solr/src/main/java/eu/iksproject/rick/yard/solr/impl/SolrQueryFactory.java (original)
+++ incubator/stanbol/trunk/rick/yard/solr/src/main/java/eu/iksproject/rick/yard/solr/impl/SolrQueryFactory.java Sun Dec 12 15:13:35 2010
@@ -54,7 +54,7 @@ import eu.iksproject.rick.yard.solr.util
  * as used to index the documents in the index must be parsed. <p>
  * TODO: This class currently contains the <ul>
  * <li> general usable functionality to convert {@link Query} instances to
- * the according representation in index constraints (see 
+ * the according representation in index constraints (see
  * {@link IndexConstraintTypeEnum} and {@link IndexConstraint}
  * <li> general usable functionality to combine the constraints to an tree of
  * AND and OR constraints
@@ -65,509 +65,509 @@ import eu.iksproject.rick.yard.solr.util
  * </ul>
  * Splitting such things up in several different components should make it easy
  * to add support for other DocumentStores!
- * 
+ *
  * @author Rupert Westenthaler
  *
  */
 public class SolrQueryFactory {
 
-	/**
-	 * Allows to limit the maximum Numbers of Query Results for any kind of Query.
-	 * For now it is set to 1024.
-	 */
-	public static final Integer MAX_QUERY_RESULTS = 1024;
-	/**
-	 * The default limit of results for queries
-	 */
-	public static final Integer DEFAULT_QUERY_RESULTS = 10;
-	protected final Logger log = LoggerFactory.getLogger(SolrQueryFactory.class);
-	private final FieldMapper fieldMapper;
-	private final IndexValueFactory indexValueFactory;
-	private final ValueFactory valueFactory;
-	protected final Map<IndexConstraintTypeEnum, IndexConstraintTypeEncoder<?>> constraintEncoders;
-
-	protected String domain;
-	protected Integer maxQueryResults = MAX_QUERY_RESULTS;
-	protected Integer defaultQueryResults = DEFAULT_QUERY_RESULTS;
-
-	public SolrQueryFactory(ValueFactory valueFactory, IndexValueFactory indexValueFactory, FieldMapper fieldMapper){
-		if(fieldMapper == null){
-			throw new IllegalArgumentException("The parsed FieldMapper MUST NOT be NULL!");
-		}
-		if(indexValueFactory == null){
-			throw new IllegalArgumentException("The parsed IndexValueFactory MUST NOT be NULL!");
-		}
-		if(valueFactory == null){
-			throw new IllegalArgumentException("The parsed ValueFactory MUST NOT be NULL");
-		}
-		this.valueFactory = valueFactory;
-		this.fieldMapper = fieldMapper;
-		this.indexValueFactory = indexValueFactory;
-		this.constraintEncoders = new HashMap<IndexConstraintTypeEnum, IndexConstraintTypeEncoder<?>>();
-		//TODO: Make this configuration more flexible!
-		constraintEncoders.put(IndexConstraintTypeEnum.LANG, new LangEncoder(fieldMapper));
-		constraintEncoders.put(IndexConstraintTypeEnum.DATATYPE, new DataTypeEncoder(indexValueFactory,fieldMapper));
-		constraintEncoders.put(IndexConstraintTypeEnum.FIELD, new FieldEncoder(fieldMapper));
-		constraintEncoders.put(IndexConstraintTypeEnum.EQ, new AssignmentEncoder(indexValueFactory));
-		constraintEncoders.put(IndexConstraintTypeEnum.WILDCARD, new WildcardEncoder());
-		constraintEncoders.put(IndexConstraintTypeEnum.REGEX, new RegexEncoder());
-		constraintEncoders.put(IndexConstraintTypeEnum.GE, new GeEncoder(indexValueFactory));
-		constraintEncoders.put(IndexConstraintTypeEnum.LE, new LeEncoder(indexValueFactory));
-		constraintEncoders.put(IndexConstraintTypeEnum.GT, new GtEncoder(indexValueFactory));
-		constraintEncoders.put(IndexConstraintTypeEnum.LT, new LtEncoder(indexValueFactory));
-	}
-	public static enum SELECT {ID,QUERY,ALL}
-	public SolrQuery parseFieldQuery(FieldQuery fieldQuery,SELECT select){
-		SolrQuery query = initSolrQuery(fieldQuery);
-		setSelected(query, fieldQuery.getSelectedFields(),select);
-		StringBuilder queryString = new StringBuilder();
-		for(Entry<String, Constraint> fieldConstraint : fieldQuery){
-			IndexConstraint indexConstraint = createIndexConstraint(fieldConstraint);
-			if(indexConstraint.isInvalied()){
-				log.warn(String.format("Unable to create IndexConstraint for Constraint %s (type: %s) and Field %s (Reosens: %s)",
-						fieldConstraint.getValue(),fieldConstraint.getValue().getType(),fieldConstraint.getKey(),
-						indexConstraint.getInvalidMessages()));
-			} else {
-				if(queryString.length()>0){
-					queryString.append(" AND ");
-				}
-				indexConstraint.encode(queryString);
-			}
-		}
-		log.info("QueryStirng: "+queryString.toString());
-		query.setQuery(queryString.toString());
-		return query;
-	}
-	/**
-	 * TODO: Currently I have no Idea how to determine all the fields to be
-	 * selected, because There are any number of possibilities for field
-	 * names in the index (different data types, different languages ...).
-	 * Therefore currently I select all fields and apply the filter when
-	 * converting the {@link SolrDocument}s in the result to the 
-	 * {@link Representation}.<p>
-	 * The only thing I can do is to select only the ID if an empty list is
-	 * parsed as selected.
-	 * @param query
-	 * @param selected
-	 */
-	private void setSelected(SolrQuery query, Collection<String> selected,SELECT select){
-		switch (select) {
-		case ID:
-			query.addField(fieldMapper.getDocumentIdField());
-			break;
-		case QUERY:
-			if(selected.isEmpty()){
-				query.addField(fieldMapper.getDocumentIdField());
-			} else {
-				query.addField("*");
-				//See to do in java doc of this method
-//				for(String field : selected){
-//					if(field != null && !field.isEmpty()){
-//						fieldMapper.getFieldNames(new IndexField(Arrays.asList(field), null, null));
-//					}
-//				}
-			}
-			break;
-		case ALL:
-			query.addField("*");
-			break;
-		default:
-			throw new IllegalArgumentException(
-					String.format("Unknown SELECT status %s! Adapt this implementation to the new value of the Enumeration",
-							select));
-		}
-		//add the select for the score
-		query.addField("score");
-	}
-	private IndexConstraint createIndexConstraint(Entry<String, Constraint> fieldConstraint){
-		IndexConstraint indexConstraint = new IndexConstraint(Arrays.asList(fieldConstraint.getKey()));
-		switch(fieldConstraint.getValue().getType()){
-		case value:
-			initIndexConstraint(indexConstraint, (ValueConstraint)fieldConstraint.getValue());
-			break;
-		case text:
-			initIndexConstraint(indexConstraint, (TextConstraint) fieldConstraint.getValue());
-			break;
-		case range:
-			initIndexConstraint(indexConstraint, (RangeConstraint)fieldConstraint.getValue());
-			break;
-		default:
-			indexConstraint.setInvalied(String.format("ConstraintType %s not supported by!",
-					fieldConstraint.getValue().getType()));
-				
-		}
-		return indexConstraint;
-	}
-
-	/**
-	 * @param indexConstraint
-	 * @param rangeConstraint
-	 */
-	private void initIndexConstraint(IndexConstraint indexConstraint, RangeConstraint rangeConstraint) {
-		//we need to find the Index DataType for the range query
-		IndexDataType dataType = null;
-		if(rangeConstraint.getLowerBound() != null){
-			dataType = indexValueFactory.createIndexValue(rangeConstraint.getLowerBound()).getType();
-		}
-		if(rangeConstraint.getUpperBound() != null){
-			IndexDataType upperDataType = indexValueFactory.createIndexValue(rangeConstraint.getUpperBound()).getType();
-			if(dataType == null){
-				dataType = upperDataType;
-			} else {
-				if(dataType != upperDataType){
-					indexConstraint.setInvalied(String.format("A Range Query MUST use the same data type for the upper and lover Bound! (lower:[value=%s|datatype=%s] | upper:[value=%s|datatype=%s])",
-							rangeConstraint.getLowerBound(),dataType,rangeConstraint.getUpperBound(),upperDataType));
-				}
-			}
-		}
-		if(dataType == null){
-			indexConstraint.setInvalied("A Range Constraint MUST define at least a lower or an upper bound!");
-		} else {
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, dataType);
-		}
-		if(rangeConstraint.isInclusive()){
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.LE, rangeConstraint.getUpperBound());
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.GE, rangeConstraint.getLowerBound());
-		} else {
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.LT, rangeConstraint.getUpperBound());
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.GT, rangeConstraint.getLowerBound());
-		}
-	}
-
-	/**
-	 * @param indexConstraint
-	 * @param textConstraint
-	 */
-	private void initIndexConstraint(IndexConstraint indexConstraint, TextConstraint textConstraint) {
-		Text text = valueFactory.createText(textConstraint.getText());
-		indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, text);
-		indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.LANG, textConstraint.getLanguages());
-		switch (textConstraint.getPatternType()) {
-		case none:
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.EQ, text);
-			break;
-		case wildcard:
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.WILDCARD, textConstraint.getText());
-			break;
-		case regex:
-			indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.REGEX, textConstraint.getText());
-			break;
-		default:
-			indexConstraint.setInvalied(String.format("PatterType %s not supported for Solr Index Queries!",
-					textConstraint.getPatternType()));
-		}
-	}
-
-	/**
-	 * @param indexConstraint
-	 * @param refConstraint
-	 */
-	private void initIndexConstraint(IndexConstraint indexConstraint, ValueConstraint valueConstraint) {
-		if(valueConstraint.getValue() == null){
-			indexConstraint.setInvalied(String.format("ValueConstraint without a value - that check only any value for the parsed datatypes %s is present - can not be supported by a Solr query!",valueConstraint.getDataTypes()));
-		} else {
-			//first process the parsed dataTypes to get the supported types
-			Collection<IndexDataType> indexDataTypes = new HashSet<IndexDataType>();
-			if(valueConstraint.getDataTypes() != null){
-				for(String dataType : valueConstraint.getDataTypes()){
-					IndexDataTypeEnum indexDataTypeEnumEntry = IndexDataTypeEnum.forUri(dataType);
-					if(indexDataTypeEnumEntry != null){
-						indexDataTypes.add(indexDataTypeEnumEntry.getIndexType());
-					} else {
-						//TODO: Add possibility to add warnings to indexConstraints
-						log.warn(String.format("A Datatype parsed for a ValueConstraint is not supported and will be ignored (dataTypeUri=%s)",
-								dataType));
-					}
-				}
-			}
-			if(indexDataTypes.isEmpty()){ //if no supported types are present
-				//get the dataType based on the type of the value
-				try {
-					IndexValue indexValue = indexValueFactory.createIndexValue(valueConstraint.getValue());
-					indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.EQ, indexValue);
-					indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, indexValue);
-				}catch (NoConverterException e) {
-					indexConstraint.setInvalied(e.getMessage());
-				}
-			} else { //one or more supported dataTypes are present
-				for(IndexDataType indexDataType : indexDataTypes){
-					indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, indexDataType);
-				}
-				/*
-				 * NOTE: add only a single EQ constraints, because if different
-				 *       dataTypes would result in different representations of
-				 *       the parsed value this code would not work altogether!
-				 */
-				IndexValue indexValue;
-				try { //use the default converter for the value
-					indexValue = indexValueFactory.createIndexValue(valueConstraint.getValue());
-				}catch (NoConverterException e) {
-					//if not found use the toString() and the first parsed DataType
-					IndexDataType indexDataType = indexDataTypes.iterator().next();
-					log.warn(String.format("Unable to create IndexValue for value %s (type: %s). Create IndexValue manually by using the first parsed IndexDataType %s",
-							valueConstraint.getValue(),valueConstraint.getValue().getClass(),indexDataType));
-					indexValue = new IndexValue(valueConstraint.getValue().toString(),indexDataType);
-				}
-				indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.EQ, indexValue);
-			}
-		}
-	}
-
-	private SolrQuery initSolrQuery(Query rickQuery){
-		SolrQuery query = new SolrQuery();
-		//first add a filterquery for the domain if present
-		if(domain != null){
-			query.addFilterQuery(String.format("%s:%s", 
-					fieldMapper.getDocumentDomainField(),SolrUtil.escapeSolrSpecialChars(domain)));
-		}
-		//than add the offset
-		query.setStart(rickQuery.getOffset());
-		//and the limit
-		if(rickQuery.getLimit() != null){
-			if(rickQuery.getLimit().compareTo(MAX_QUERY_RESULTS)<=0){
-				query.setRows(rickQuery.getLimit());
-			} else {
-				log.warn(String.format("Parsed Number of QueryResults %d is greater than the allowed maximum of %d!",
-						rickQuery.getLimit(),MAX_QUERY_RESULTS));
-			}
-		} else {
-			//maybe remove that to prevent to many results! But for now I would
-			//rather like to have a default value within the FieldQuery!
-			//e.g. set by the FieldQueryFactory when creating new queries!
-			query.setRows(MAX_QUERY_RESULTS);
-		}
-		return query;
-	}
-	/**
-	 * Getter for the domain set as FilterQuery to all generated SolrQueries
-	 * @return the domain or <code>null</code> if no domain is set
-	 */
-	public final String getDomain() {
-		return domain;
-	}
-	/**
-	 * Setter for the domain. If an empty string is parsed, than the domain is
-	 * set to <code>null</code>, otherwise the parsed value is set. Parse
-	 * <code>null</code> to deactivated the usage of domains
-	 * @param domain the domain or <code>null</code> if no domain is active
-	 */
-	public final void setDomain(String domain) {
-		if(domain != null && domain.isEmpty()){
-			this.domain = null;
-		} else {
-			this.domain = domain;
-		}
-	}
-	/**
-	 * getter for the maximum number of results allowed
-	 * @return the maximum number of results that can be set
-	 */
-	public final Integer getMaxQueryResults() {
-		return maxQueryResults;
-	}
-	/**
-	 * Setter for the maximum number of results allowed. If <code>null</code> is
-	 * parsed than the value is set to {@link #MAX_QUERY_RESULTS}. If a value
-	 * smaller than {@link #getDefaultQueryResults()} is parsed, than the
-	 * value is set to {@link #getDefaultQueryResults()}.
-	 * @param maxQueryResults The maximum number of queries allowed
-	 */
-	public final void setMaxQueryResults(Integer maxQueryResults) {
-		if(maxQueryResults == null){
-			this.maxQueryResults = MAX_QUERY_RESULTS;
-		} else if(maxQueryResults.compareTo(defaultQueryResults)<=0){
-			this.maxQueryResults = defaultQueryResults;
-		} else {
-			this.maxQueryResults = maxQueryResults;
-		}
-	}
-	/**
-	 * Getter for the default number of query results. This is used if a parsed
-	 * Query does not define the number of results.
-	 * @return the default value for the number of query results
-	 */
-	public final Integer getDefaultQueryResults() {
-		return defaultQueryResults;
-	}
-	/**
-	 * Setter for the default number of query results. This is used if a parsed
-	 * Query does not define the number of results. If <code>null</code> or a 
-	 * value <code><= 0</code>is parsed, than the value is set to the lower value 
-	 * of {@link #DEFAULT_QUERY_RESULTS} ({@value #DEFAULT_QUERY_RESULTS}) and
-	 * {@link #getMaxQueryResults()}. If a value <code>>=</code> 
-	 * {@link #getMaxQueryResults()} is parsed, than the value is set to
-	 * {@link #getMaxQueryResults()}.
-	 * @param defaultQueryResults the default number of results for queries
-	 */
-	public final void setDefaultQueryResults(Integer defaultQueryResults) {
-		if(defaultQueryResults == null || defaultQueryResults.intValue()<=0){
-			this.defaultQueryResults = Math.min(DEFAULT_QUERY_RESULTS, maxQueryResults);
-		} else if(defaultQueryResults.compareTo(maxQueryResults)>=0){
-			this.defaultQueryResults = maxQueryResults;
-		} else {
-			this.defaultQueryResults = defaultQueryResults;
-		}
-	}
-	/**
-	 * Class internally used to process FieldConstraint. This class accesses
-	 * the {@link SolrQueryFactory#constraintEncoders} map.
-	 * @author Rupert Westenthaler
-	 *
-	 */
-	private class IndexConstraint {
-		private final Map<IndexConstraintTypeEnum,Object> fieldConstraints = new EnumMap<IndexConstraintTypeEnum,Object>(IndexConstraintTypeEnum.class);
-		private List<String> invaliedMessages = new ArrayList<String>();
-		/**
-		 * Creates a Field Term for the parsed path
-		 * @param path the path
-		 * @throws IllegalArgumentException If the path is <code>null</code> empty.
-		 */
-		public IndexConstraint(List<String> field) throws IllegalArgumentException{
-			if(field == null || field.isEmpty()){
-				throw new IllegalArgumentException("The parsed path MUST NOT be NULL nor empty!");
-			}
-			fieldConstraints.put(IndexConstraintTypeEnum.FIELD, field);
-		}
-		/**
-		 * Set to <code>true</code> to indicate, that this IndexConstraint can not
-		 * be used. e.g. if the conversion of a {@link Constraint } to an
-		 * {@link IndexConstraint} was unsuccessful!
-		 * @param state the state
-		 */
-		public void setInvalied(String message) {
-			this.invaliedMessages.add(message);
-			
-		}
-		/**
-		 * Returns <code>true</code> if this index constraint is invalid and
-		 * can not be used for the IndexQuery. If the state is <code>true</code>
-		 * it indicates, that the conversion to a {@link Constraint } to an
-		 * {@link IndexConstraint} was not successful!
-		 * @return the state
-		 */
-		public boolean isInvalied(){
-			return !invaliedMessages.isEmpty();
-		}
-		/**
-		 * Getter for the Messages why this index constraint is not valid
-		 * @return the messages. An empty List if {@link #isInvalied()} returns
-		 * <code>false</code>
-		 */
-		public List<String> getInvalidMessages(){
-			return invaliedMessages;
-		}
-		/**
-		 * Sets an IndexConstraintType to a specific value
-		 * @param constraintType the type of the constraint
-		 * @param value the value. <code>null</code> is permitted, but usually it is
-		 * not needed to add <code>null</code> constraints, because they are automatically
-		 * added if needed (e.g. a range constraint with an open lower bound)
-		 * @throws IllegalArgumentException if <code>null</code> is parsed as constraint type
-		 */
-		public void setFieldConstraint(IndexConstraintTypeEnum constraintType,Object value) throws IllegalArgumentException {
-			if(constraintType == null){
-				//just returning here would also be OK, but better to find errors early by
-				//looking at stack traces
-				throw new IllegalArgumentException("Parameter IndexConstraintTypeEnum MUST NOT be NULL");
-			}
-			IndexConstraintTypeEncoder<?> encoder = constraintEncoders.get(constraintType);
-			if(encoder == null){
-				throw new IllegalArgumentException(String.format("No Encoder for IndexConstraintType %s present!",constraintType));
-			}
-			//accept null values and values that are supported by the encoder!
-			if(value == null || encoder.acceptsValueType().isAssignableFrom(value.getClass())){
-				this.fieldConstraints.put(constraintType, value);
-				//we need also check the dependent types!
-				for(IndexConstraintTypeEnum dependent : encoder.dependsOn()){
-					//if a dependent type is missing, add it with the default value!
-					if(!fieldConstraints.containsKey(dependent)){
-						//if missing, set the dependent to null (default value)
-						setFieldConstraint(dependent, null);
-					}
-				}
-			} else {
-				throw new IllegalArgumentException(
-						String.format("The Encoder %s for IndexConstraintType %s does not support values of type %s (supported Type: %s)!",
-								encoder.getClass(),constraintType,value.getClass(),encoder.acceptsValueType()));
-			}
-		}
-		@SuppressWarnings("unchecked")
-		public void encode(StringBuilder queryString) {
-			if(isInvalied()){
-				throw new IllegalStateException(String.format("Unable to encode an invalid IndexConstraint (invalid messages: %s)",getInvalidMessages()));
-			} else {
-				EncodedConstraintParts encodedConstraintParts = new EncodedConstraintParts();
-				for(Entry<IndexConstraintTypeEnum, Object> constraint : fieldConstraints.entrySet()){
-					//NOTE: type checks are already performed in the setFieldConstraint method!
-					((IndexConstraintTypeEncoder<Object>)constraintEncoders.get(constraint.getKey())).
-						encode(encodedConstraintParts, constraint.getValue());
-				}
-				//now take the parts and create the constraint!
-				encodeSolrConstraint(queryString,encodedConstraintParts);
-			}
-			
-		}
-		private StringBuilder encodeSolrConstraint(StringBuilder queryString,EncodedConstraintParts encodedConstraintParts) {
-			//list of all constraints that need to be connected with OR
-			List<StringBuilder> constraints = new ArrayList<StringBuilder>();
-			//init with a single constraint
-			constraints.add(new StringBuilder());
-			for(Entry<ConstraintTypePosition, Set<String>> entry : encodedConstraintParts){
-				//one position may contain multiple options that need to be connected with OR
-				Set<String> parts = entry.getValue();
-				int i=0;
-				int constraintsSize = constraints.size();
-				for(String part : parts){
-					i++;
-					if(i == parts.size()){
-						//for the last iteration, append the part to the existing constraints
-						for(int j=0;j<constraintsSize;j++){
-							constraints.get(j).append(part);
-						}
-					} else {
-						//if there is more than one value, we need to generate new variants for
-						//every option other than the last.
-						for(int j=0;j<constraintsSize;j++){
-							StringBuilder additional = new StringBuilder(constraints.get(j));
-							additional.append(part);
-							constraints.add(additional);
-						}
-					}
-				}
-			}
-			//now combine the different options to a single query string
-			boolean first = true;
-			for(StringBuilder constraint : constraints){
-				if(constraint.length()>0){
-					if(first){
-						queryString.append('(');
-						first = false;
-					} else {
-						queryString.append(" OR ");
-					}
-					queryString.append(constraint);
-				} //else ignore empty constraints
-			}
-			if(!first){
-				queryString.append(')');
-			}
-			return queryString;
-		}
-		
-//		/**
-//		 * NOTE: removed, because currently not needed. If re-added, this Method needs also
-//		 *       to remove (recursively) dependent with the default value
-//		 * Removes the according index constraint if present
-//		 * @param constraintType the constraint to remove
-//		 * @throws IllegalArgumentException if <code>null</code> is parsed as constraint type
-//		 */
-//		public void removeFieldConstraint(IndexConstraintTypeEnum constraintType) throws IllegalArgumentException {
-//			if(constraintType == null){
-//				//just returning here would also be OK, but better to find errors early by
-//				//looking at stack traces
-//				throw new IllegalArgumentException("Parameter IndexConstraintTypeEnum MUST NOT be NULL");
-//			}
-//			this.fieldConstraints.remove(constraintType);
-//		}
-	}	
+    /**
+     * Allows to limit the maximum Numbers of Query Results for any kind of Query.
+     * For now it is set to 1024.
+     */
+    public static final Integer MAX_QUERY_RESULTS = 1024;
+    /**
+     * The default limit of results for queries
+     */
+    public static final Integer DEFAULT_QUERY_RESULTS = 10;
+    protected final Logger log = LoggerFactory.getLogger(SolrQueryFactory.class);
+    private final FieldMapper fieldMapper;
+    private final IndexValueFactory indexValueFactory;
+    private final ValueFactory valueFactory;
+    protected final Map<IndexConstraintTypeEnum, IndexConstraintTypeEncoder<?>> constraintEncoders;
+
+    protected String domain;
+    protected Integer maxQueryResults = MAX_QUERY_RESULTS;
+    protected Integer defaultQueryResults = DEFAULT_QUERY_RESULTS;
+
+    public SolrQueryFactory(ValueFactory valueFactory, IndexValueFactory indexValueFactory, FieldMapper fieldMapper){
+        if(fieldMapper == null){
+            throw new IllegalArgumentException("The parsed FieldMapper MUST NOT be NULL!");
+        }
+        if(indexValueFactory == null){
+            throw new IllegalArgumentException("The parsed IndexValueFactory MUST NOT be NULL!");
+        }
+        if(valueFactory == null){
+            throw new IllegalArgumentException("The parsed ValueFactory MUST NOT be NULL");
+        }
+        this.valueFactory = valueFactory;
+        this.fieldMapper = fieldMapper;
+        this.indexValueFactory = indexValueFactory;
+        this.constraintEncoders = new HashMap<IndexConstraintTypeEnum, IndexConstraintTypeEncoder<?>>();
+        //TODO: Make this configuration more flexible!
+        constraintEncoders.put(IndexConstraintTypeEnum.LANG, new LangEncoder(fieldMapper));
+        constraintEncoders.put(IndexConstraintTypeEnum.DATATYPE, new DataTypeEncoder(indexValueFactory,fieldMapper));
+        constraintEncoders.put(IndexConstraintTypeEnum.FIELD, new FieldEncoder(fieldMapper));
+        constraintEncoders.put(IndexConstraintTypeEnum.EQ, new AssignmentEncoder(indexValueFactory));
+        constraintEncoders.put(IndexConstraintTypeEnum.WILDCARD, new WildcardEncoder());
+        constraintEncoders.put(IndexConstraintTypeEnum.REGEX, new RegexEncoder());
+        constraintEncoders.put(IndexConstraintTypeEnum.GE, new GeEncoder(indexValueFactory));
+        constraintEncoders.put(IndexConstraintTypeEnum.LE, new LeEncoder(indexValueFactory));
+        constraintEncoders.put(IndexConstraintTypeEnum.GT, new GtEncoder(indexValueFactory));
+        constraintEncoders.put(IndexConstraintTypeEnum.LT, new LtEncoder(indexValueFactory));
+    }
+    public static enum SELECT {ID,QUERY,ALL}
+    public SolrQuery parseFieldQuery(FieldQuery fieldQuery,SELECT select){
+        SolrQuery query = initSolrQuery(fieldQuery);
+        setSelected(query, fieldQuery.getSelectedFields(),select);
+        StringBuilder queryString = new StringBuilder();
+        for(Entry<String, Constraint> fieldConstraint : fieldQuery){
+            IndexConstraint indexConstraint = createIndexConstraint(fieldConstraint);
+            if(indexConstraint.isInvalied()){
+                log.warn(String.format("Unable to create IndexConstraint for Constraint %s (type: %s) and Field %s (Reosens: %s)",
+                        fieldConstraint.getValue(),fieldConstraint.getValue().getType(),fieldConstraint.getKey(),
+                        indexConstraint.getInvalidMessages()));
+            } else {
+                if(queryString.length()>0){
+                    queryString.append(" AND ");
+                }
+                indexConstraint.encode(queryString);
+            }
+        }
+        log.info("QueryStirng: "+queryString.toString());
+        query.setQuery(queryString.toString());
+        return query;
+    }
+    /**
+     * TODO: Currently I have no Idea how to determine all the fields to be
+     * selected, because There are any number of possibilities for field
+     * names in the index (different data types, different languages ...).
+     * Therefore currently I select all fields and apply the filter when
+     * converting the {@link SolrDocument}s in the result to the
+     * {@link Representation}.<p>
+     * The only thing I can do is to select only the ID if an empty list is
+     * parsed as selected.
+     * @param query
+     * @param selected
+     */
+    private void setSelected(SolrQuery query, Collection<String> selected,SELECT select){
+        switch (select) {
+        case ID:
+            query.addField(fieldMapper.getDocumentIdField());
+            break;
+        case QUERY:
+            if(selected.isEmpty()){
+                query.addField(fieldMapper.getDocumentIdField());
+            } else {
+                query.addField("*");
+                //See to do in java doc of this method
+//                for(String field : selected){
+//                    if(field != null && !field.isEmpty()){
+//                        fieldMapper.getFieldNames(new IndexField(Arrays.asList(field), null, null));
+//                    }
+//                }
+            }
+            break;
+        case ALL:
+            query.addField("*");
+            break;
+        default:
+            throw new IllegalArgumentException(
+                    String.format("Unknown SELECT status %s! Adapt this implementation to the new value of the Enumeration",
+                            select));
+        }
+        //add the select for the score
+        query.addField("score");
+    }
+    private IndexConstraint createIndexConstraint(Entry<String, Constraint> fieldConstraint){
+        IndexConstraint indexConstraint = new IndexConstraint(Arrays.asList(fieldConstraint.getKey()));
+        switch(fieldConstraint.getValue().getType()){
+        case value:
+            initIndexConstraint(indexConstraint, (ValueConstraint)fieldConstraint.getValue());
+            break;
+        case text:
+            initIndexConstraint(indexConstraint, (TextConstraint) fieldConstraint.getValue());
+            break;
+        case range:
+            initIndexConstraint(indexConstraint, (RangeConstraint)fieldConstraint.getValue());
+            break;
+        default:
+            indexConstraint.setInvalied(String.format("ConstraintType %s not supported by!",
+                    fieldConstraint.getValue().getType()));
+
+        }
+        return indexConstraint;
+    }
+
+    /**
+     * @param indexConstraint
+     * @param rangeConstraint
+     */
+    private void initIndexConstraint(IndexConstraint indexConstraint, RangeConstraint rangeConstraint) {
+        //we need to find the Index DataType for the range query
+        IndexDataType dataType = null;
+        if(rangeConstraint.getLowerBound() != null){
+            dataType = indexValueFactory.createIndexValue(rangeConstraint.getLowerBound()).getType();
+        }
+        if(rangeConstraint.getUpperBound() != null){
+            IndexDataType upperDataType = indexValueFactory.createIndexValue(rangeConstraint.getUpperBound()).getType();
+            if(dataType == null){
+                dataType = upperDataType;
+            } else {
+                if(dataType != upperDataType){
+                    indexConstraint.setInvalied(String.format("A Range Query MUST use the same data type for the upper and lover Bound! (lower:[value=%s|datatype=%s] | upper:[value=%s|datatype=%s])",
+                            rangeConstraint.getLowerBound(),dataType,rangeConstraint.getUpperBound(),upperDataType));
+                }
+            }
+        }
+        if(dataType == null){
+            indexConstraint.setInvalied("A Range Constraint MUST define at least a lower or an upper bound!");
+        } else {
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, dataType);
+        }
+        if(rangeConstraint.isInclusive()){
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.LE, rangeConstraint.getUpperBound());
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.GE, rangeConstraint.getLowerBound());
+        } else {
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.LT, rangeConstraint.getUpperBound());
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.GT, rangeConstraint.getLowerBound());
+        }
+    }
+
+    /**
+     * @param indexConstraint
+     * @param textConstraint
+     */
+    private void initIndexConstraint(IndexConstraint indexConstraint, TextConstraint textConstraint) {
+        Text text = valueFactory.createText(textConstraint.getText());
+        indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, text);
+        indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.LANG, textConstraint.getLanguages());
+        switch (textConstraint.getPatternType()) {
+        case none:
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.EQ, text);
+            break;
+        case wildcard:
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.WILDCARD, textConstraint.getText());
+            break;
+        case regex:
+            indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.REGEX, textConstraint.getText());
+            break;
+        default:
+            indexConstraint.setInvalied(String.format("PatterType %s not supported for Solr Index Queries!",
+                    textConstraint.getPatternType()));
+        }
+    }
+
+    /**
+     * @param indexConstraint
+     * @param refConstraint
+     */
+    private void initIndexConstraint(IndexConstraint indexConstraint, ValueConstraint valueConstraint) {
+        if(valueConstraint.getValue() == null){
+            indexConstraint.setInvalied(String.format("ValueConstraint without a value - that check only any value for the parsed datatypes %s is present - can not be supported by a Solr query!",valueConstraint.getDataTypes()));
+        } else {
+            //first process the parsed dataTypes to get the supported types
+            Collection<IndexDataType> indexDataTypes = new HashSet<IndexDataType>();
+            if(valueConstraint.getDataTypes() != null){
+                for(String dataType : valueConstraint.getDataTypes()){
+                    IndexDataTypeEnum indexDataTypeEnumEntry = IndexDataTypeEnum.forUri(dataType);
+                    if(indexDataTypeEnumEntry != null){
+                        indexDataTypes.add(indexDataTypeEnumEntry.getIndexType());
+                    } else {
+                        //TODO: Add possibility to add warnings to indexConstraints
+                        log.warn(String.format("A Datatype parsed for a ValueConstraint is not supported and will be ignored (dataTypeUri=%s)",
+                                dataType));
+                    }
+                }
+            }
+            if(indexDataTypes.isEmpty()){ //if no supported types are present
+                //get the dataType based on the type of the value
+                try {
+                    IndexValue indexValue = indexValueFactory.createIndexValue(valueConstraint.getValue());
+                    indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.EQ, indexValue);
+                    indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, indexValue);
+                }catch (NoConverterException e) {
+                    indexConstraint.setInvalied(e.getMessage());
+                }
+            } else { //one or more supported dataTypes are present
+                for(IndexDataType indexDataType : indexDataTypes){
+                    indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.DATATYPE, indexDataType);
+                }
+                /*
+                 * NOTE: add only a single EQ constraints, because if different
+                 *       dataTypes would result in different representations of
+                 *       the parsed value this code would not work altogether!
+                 */
+                IndexValue indexValue;
+                try { //use the default converter for the value
+                    indexValue = indexValueFactory.createIndexValue(valueConstraint.getValue());
+                }catch (NoConverterException e) {
+                    //if not found use the toString() and the first parsed DataType
+                    IndexDataType indexDataType = indexDataTypes.iterator().next();
+                    log.warn(String.format("Unable to create IndexValue for value %s (type: %s). Create IndexValue manually by using the first parsed IndexDataType %s",
+                            valueConstraint.getValue(),valueConstraint.getValue().getClass(),indexDataType));
+                    indexValue = new IndexValue(valueConstraint.getValue().toString(),indexDataType);
+                }
+                indexConstraint.setFieldConstraint(IndexConstraintTypeEnum.EQ, indexValue);
+            }
+        }
+    }
+
+    private SolrQuery initSolrQuery(Query rickQuery){
+        SolrQuery query = new SolrQuery();
+        //first add a filterquery for the domain if present
+        if(domain != null){
+            query.addFilterQuery(String.format("%s:%s",
+                    fieldMapper.getDocumentDomainField(),SolrUtil.escapeSolrSpecialChars(domain)));
+        }
+        //than add the offset
+        query.setStart(rickQuery.getOffset());
+        //and the limit
+        if(rickQuery.getLimit() != null){
+            if(rickQuery.getLimit().compareTo(MAX_QUERY_RESULTS)<=0){
+                query.setRows(rickQuery.getLimit());
+            } else {
+                log.warn(String.format("Parsed Number of QueryResults %d is greater than the allowed maximum of %d!",
+                        rickQuery.getLimit(),MAX_QUERY_RESULTS));
+            }
+        } else {
+            //maybe remove that to prevent to many results! But for now I would
+            //rather like to have a default value within the FieldQuery!
+            //e.g. set by the FieldQueryFactory when creating new queries!
+            query.setRows(MAX_QUERY_RESULTS);
+        }
+        return query;
+    }
+    /**
+     * Getter for the domain set as FilterQuery to all generated SolrQueries
+     * @return the domain or <code>null</code> if no domain is set
+     */
+    public final String getDomain() {
+        return domain;
+    }
+    /**
+     * Setter for the domain. If an empty string is parsed, than the domain is
+     * set to <code>null</code>, otherwise the parsed value is set. Parse
+     * <code>null</code> to deactivated the usage of domains
+     * @param domain the domain or <code>null</code> if no domain is active
+     */
+    public final void setDomain(String domain) {
+        if(domain != null && domain.isEmpty()){
+            this.domain = null;
+        } else {
+            this.domain = domain;
+        }
+    }
+    /**
+     * getter for the maximum number of results allowed
+     * @return the maximum number of results that can be set
+     */
+    public final Integer getMaxQueryResults() {
+        return maxQueryResults;
+    }
+    /**
+     * Setter for the maximum number of results allowed. If <code>null</code> is
+     * parsed than the value is set to {@link #MAX_QUERY_RESULTS}. If a value
+     * smaller than {@link #getDefaultQueryResults()} is parsed, than the
+     * value is set to {@link #getDefaultQueryResults()}.
+     * @param maxQueryResults The maximum number of queries allowed
+     */
+    public final void setMaxQueryResults(Integer maxQueryResults) {
+        if(maxQueryResults == null){
+            this.maxQueryResults = MAX_QUERY_RESULTS;
+        } else if(maxQueryResults.compareTo(defaultQueryResults)<=0){
+            this.maxQueryResults = defaultQueryResults;
+        } else {
+            this.maxQueryResults = maxQueryResults;
+        }
+    }
+    /**
+     * Getter for the default number of query results. This is used if a parsed
+     * Query does not define the number of results.
+     * @return the default value for the number of query results
+     */
+    public final Integer getDefaultQueryResults() {
+        return defaultQueryResults;
+    }
+    /**
+     * Setter for the default number of query results. This is used if a parsed
+     * Query does not define the number of results. If <code>null</code> or a
+     * value <code><= 0</code>is parsed, than the value is set to the lower value
+     * of {@link #DEFAULT_QUERY_RESULTS} ({@value #DEFAULT_QUERY_RESULTS}) and
+     * {@link #getMaxQueryResults()}. If a value <code>>=</code>
+     * {@link #getMaxQueryResults()} is parsed, than the value is set to
+     * {@link #getMaxQueryResults()}.
+     * @param defaultQueryResults the default number of results for queries
+     */
+    public final void setDefaultQueryResults(Integer defaultQueryResults) {
+        if(defaultQueryResults == null || defaultQueryResults.intValue()<=0){
+            this.defaultQueryResults = Math.min(DEFAULT_QUERY_RESULTS, maxQueryResults);
+        } else if(defaultQueryResults.compareTo(maxQueryResults)>=0){
+            this.defaultQueryResults = maxQueryResults;
+        } else {
+            this.defaultQueryResults = defaultQueryResults;
+        }
+    }
+    /**
+     * Class internally used to process FieldConstraint. This class accesses
+     * the {@link SolrQueryFactory#constraintEncoders} map.
+     * @author Rupert Westenthaler
+     *
+     */
+    private class IndexConstraint {
+        private final Map<IndexConstraintTypeEnum,Object> fieldConstraints = new EnumMap<IndexConstraintTypeEnum,Object>(IndexConstraintTypeEnum.class);
+        private List<String> invaliedMessages = new ArrayList<String>();
+        /**
+         * Creates a Field Term for the parsed path
+         * @param path the path
+         * @throws IllegalArgumentException If the path is <code>null</code> empty.
+         */
+        public IndexConstraint(List<String> field) throws IllegalArgumentException{
+            if(field == null || field.isEmpty()){
+                throw new IllegalArgumentException("The parsed path MUST NOT be NULL nor empty!");
+            }
+            fieldConstraints.put(IndexConstraintTypeEnum.FIELD, field);
+        }
+        /**
+         * Set to <code>true</code> to indicate, that this IndexConstraint can not
+         * be used. e.g. if the conversion of a {@link Constraint } to an
+         * {@link IndexConstraint} was unsuccessful!
+         * @param state the state
+         */
+        public void setInvalied(String message) {
+            this.invaliedMessages.add(message);
+
+        }
+        /**
+         * Returns <code>true</code> if this index constraint is invalid and
+         * can not be used for the IndexQuery. If the state is <code>true</code>
+         * it indicates, that the conversion to a {@link Constraint } to an
+         * {@link IndexConstraint} was not successful!
+         * @return the state
+         */
+        public boolean isInvalied(){
+            return !invaliedMessages.isEmpty();
+        }
+        /**
+         * Getter for the Messages why this index constraint is not valid
+         * @return the messages. An empty List if {@link #isInvalied()} returns
+         * <code>false</code>
+         */
+        public List<String> getInvalidMessages(){
+            return invaliedMessages;
+        }
+        /**
+         * Sets an IndexConstraintType to a specific value
+         * @param constraintType the type of the constraint
+         * @param value the value. <code>null</code> is permitted, but usually it is
+         * not needed to add <code>null</code> constraints, because they are automatically
+         * added if needed (e.g. a range constraint with an open lower bound)
+         * @throws IllegalArgumentException if <code>null</code> is parsed as constraint type
+         */
+        public void setFieldConstraint(IndexConstraintTypeEnum constraintType,Object value) throws IllegalArgumentException {
+            if(constraintType == null){
+                //just returning here would also be OK, but better to find errors early by
+                //looking at stack traces
+                throw new IllegalArgumentException("Parameter IndexConstraintTypeEnum MUST NOT be NULL");
+            }
+            IndexConstraintTypeEncoder<?> encoder = constraintEncoders.get(constraintType);
+            if(encoder == null){
+                throw new IllegalArgumentException(String.format("No Encoder for IndexConstraintType %s present!",constraintType));
+            }
+            //accept null values and values that are supported by the encoder!
+            if(value == null || encoder.acceptsValueType().isAssignableFrom(value.getClass())){
+                this.fieldConstraints.put(constraintType, value);
+                //we need also check the dependent types!
+                for(IndexConstraintTypeEnum dependent : encoder.dependsOn()){
+                    //if a dependent type is missing, add it with the default value!
+                    if(!fieldConstraints.containsKey(dependent)){
+                        //if missing, set the dependent to null (default value)
+                        setFieldConstraint(dependent, null);
+                    }
+                }
+            } else {
+                throw new IllegalArgumentException(
+                        String.format("The Encoder %s for IndexConstraintType %s does not support values of type %s (supported Type: %s)!",
+                                encoder.getClass(),constraintType,value.getClass(),encoder.acceptsValueType()));
+            }
+        }
+        @SuppressWarnings("unchecked")
+        public void encode(StringBuilder queryString) {
+            if(isInvalied()){
+                throw new IllegalStateException(String.format("Unable to encode an invalid IndexConstraint (invalid messages: %s)",getInvalidMessages()));
+            } else {
+                EncodedConstraintParts encodedConstraintParts = new EncodedConstraintParts();
+                for(Entry<IndexConstraintTypeEnum, Object> constraint : fieldConstraints.entrySet()){
+                    //NOTE: type checks are already performed in the setFieldConstraint method!
+                    ((IndexConstraintTypeEncoder<Object>)constraintEncoders.get(constraint.getKey())).
+                        encode(encodedConstraintParts, constraint.getValue());
+                }
+                //now take the parts and create the constraint!
+                encodeSolrConstraint(queryString,encodedConstraintParts);
+            }
+
+        }
+        private StringBuilder encodeSolrConstraint(StringBuilder queryString,EncodedConstraintParts encodedConstraintParts) {
+            //list of all constraints that need to be connected with OR
+            List<StringBuilder> constraints = new ArrayList<StringBuilder>();
+            //init with a single constraint
+            constraints.add(new StringBuilder());
+            for(Entry<ConstraintTypePosition, Set<String>> entry : encodedConstraintParts){
+                //one position may contain multiple options that need to be connected with OR
+                Set<String> parts = entry.getValue();
+                int i=0;
+                int constraintsSize = constraints.size();
+                for(String part : parts){
+                    i++;
+                    if(i == parts.size()){
+                        //for the last iteration, append the part to the existing constraints
+                        for(int j=0;j<constraintsSize;j++){
+                            constraints.get(j).append(part);
+                        }
+                    } else {
+                        //if there is more than one value, we need to generate new variants for
+                        //every option other than the last.
+                        for(int j=0;j<constraintsSize;j++){
+                            StringBuilder additional = new StringBuilder(constraints.get(j));
+                            additional.append(part);
+                            constraints.add(additional);
+                        }
+                    }
+                }
+            }
+            //now combine the different options to a single query string
+            boolean first = true;
+            for(StringBuilder constraint : constraints){
+                if(constraint.length()>0){
+                    if(first){
+                        queryString.append('(');
+                        first = false;
+                    } else {
+                        queryString.append(" OR ");
+                    }
+                    queryString.append(constraint);
+                } //else ignore empty constraints
+            }
+            if(!first){
+                queryString.append(')');
+            }
+            return queryString;
+        }
+
+//        /**
+//         * NOTE: removed, because currently not needed. If re-added, this Method needs also
+//         *       to remove (recursively) dependent with the default value
+//         * Removes the according index constraint if present
+//         * @param constraintType the constraint to remove
+//         * @throws IllegalArgumentException if <code>null</code> is parsed as constraint type
+//         */
+//        public void removeFieldConstraint(IndexConstraintTypeEnum constraintType) throws IllegalArgumentException {
+//            if(constraintType == null){
+//                //just returning here would also be OK, but better to find errors early by
+//                //looking at stack traces
+//                throw new IllegalArgumentException("Parameter IndexConstraintTypeEnum MUST NOT be NULL");
+//            }
+//            this.fieldConstraints.remove(constraintType);
+//        }
+    }
 }