/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.reuseware.sokan.index.solr;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.eclipse.emf.common.util.EList;
import org.reuseware.sokan.Constraint;
import org.reuseware.sokan.FacetedRequest;
import org.reuseware.sokan.FacetedResponse;
import org.reuseware.sokan.IndexRow;
import org.reuseware.sokan.index.util.CoreUtil;
import org.reuseware.sokan.index.util.FacetUtil;
/**
* Utility class to support facet-based queries on the Solr index.
* <p>
* Webinar: Mastering Solr 1.4 contained hints about faceted queries
* on slide 14.
* <p>
* q=index replication&facet=true
* &fq={!tag=proj}project:(luceneOR solr)
* &facet.field={!ex=proj}project
* &facet.field={!ex=src}source
*/
public final class FacetedBrowsing {
private FacetedBrowsing() { }
private static final SolrControler CONTROLER = SolrControler.INSTANCE;
private static final String AND = " AND ";
// private static final String OR = " OR ";
/**
* Query the index according to the given request.
*
* @param request the faceted request
*
* @return the query result
*/
public static FacetedResponse query(FacetedRequest request) {
SolrQuery query = buildQuery(request);
QueryResponse response = CONTROLER.query(query);
return buildResponse(response, request);
}
private static SolrQuery buildQuery(FacetedRequest request) {
// create query object
SolrQuery query = new SolrQuery();
// allow to define a keyword search on facets and values!
// String queryString = request.getKeywordSearchString();
// if (queryString != null && !queryString.equals(""))
// query.setQuery(queryString);
// maintain faceted constraints
List<Constraint> constList = request.getConstraints();
if (constList == null || constList.isEmpty()) {
return null;
}
// start building queryString
String queryString = "";
String valueString;
String field;
EList<String> valueList;
Set<String> fields = CONTROLER.getFieldNames();
boolean stop;
for (Constraint con : constList) {
valueString = ":(";
valueList = con.getValues();
field = SolrUtil.adaptField(con.getName(), fields);
if (field == null) {
continue;
}
if (valueList.size() == 0 || valueList.contains("")) {
queryString += "-" + field + ":" + "[\"\" TO *]" + AND;
} else {
stop = false;
for (String value : valueList) {
//TODO #1261: de-activated to allow complex query construction
/*if (value.contains("*")
&& (value.contains(" ") || value.startsWith("*"))) {
stop = true;
break;
}*/
if (value != null && value.contains("*")) {
queryString += field + ":" + value + AND;
stop = true;
break;
}
valueString += "\"" + value + "\" ";
}
if (stop) {
continue;
}
queryString += field + CoreUtil.trimLastChar(valueString) + ")"
+ AND;
}
}
if ("".equals(queryString)) {
return null;
}
queryString = CoreUtil.trimLastSeperator(queryString, AND);
query.setQuery(queryString);
// maintain facet fields to get facetCounts
List<String> facetFields = request.getFacetFields();
if (facetFields != null && facetFields.size() > 0) {
query.setFacet(true);
for (String facet : facetFields) {
query.addFacetField(facet);
}
}
// TODO #1142: add rows and offset parameters
CONTROLER.limit(query, request.getRows());
return query;
}
private static FacetedResponse buildResponse(QueryResponse response,
FacetedRequest request) {
if (response == null) {
return null;
}
// maintain content
List<IndexRow> content = SolrUtil.toIndexRows(response.getResults());
// maintain value Counts
Map<String, Map<String, Long>> facetCounts;
Map<String, Long> valueCounts;
List<FacetField.Count> values;
List<FacetField> fields = response.getFacetFields();
if (fields != null) {
facetCounts = new HashMap<String, Map<String, Long>>(fields.size());
for (FacetField facetField : fields) {
values = facetField.getValues();
valueCounts = new HashMap<String, Long>(values.size());
for (FacetField.Count value : values) {
valueCounts.put(value.getName(), value.getCount());
}
facetCounts.put(facetField.getName(), valueCounts);
}
} else {
facetCounts = Collections.emptyMap();
}
// TODO #1142: support rows and offset here!
return FacetUtil.buildFacetedResponse(request, content, facetCounts);
}
}