diff --git a/pom.xml b/pom.xml
index 47843f0..f4880d5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
org.dspacedspace-solr-parentApache Solr Parent POM
- 3.5.0.1-SNAPSHOT
+ 3.5.0.1Apache Solr Parent POMhttp://lucene.apache.org/solrpom
diff --git a/webapp/pom.xml b/webapp/pom.xml
index 141ec26..3ffd4ce 100644
--- a/webapp/pom.xml
+++ b/webapp/pom.xml
@@ -20,13 +20,13 @@
org.dspacedspace-solr-parent
- 3.5.0.1-SNAPSHOT
+ 3.5.0.1org.dspacedspace-solrApache Solr Webapp
- 3.5.0.1-SNAPSHOT
+ 3.5.0.1Apache Solr Serverwar
@@ -43,6 +43,13 @@
org.apache.solrsolr
+
+
+ WEB-INF/lib/apache-solr-core-3.5.0.jar
+
@@ -89,6 +96,12 @@
3.5.0war
+
+ org.apache.solr
+ solr-core
+ 3.5.0
+ jar
+ commons-logging
diff --git a/webapp/src/main/java/org/apache/solr/handler/component/FacetComponent.java b/webapp/src/main/java/org/apache/solr/handler/component/FacetComponent.java
new file mode 100644
index 0000000..a850f44
--- /dev/null
+++ b/webapp/src/main/java/org/apache/solr/handler/component/FacetComponent.java
@@ -0,0 +1,839 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.handler.component;
+
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.util.OpenBitSet;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.FacetParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.request.SimpleFacets;
+import org.apache.solr.schema.FieldType;
+import org.apache.solr.search.QueryParsing;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * TODO!
+ *
+ * @version $Id: FacetComponent.java 1152531 2011-07-31 00:43:33Z koji $
+ * @since solr 1.3
+ */
+public class FacetComponent extends SearchComponent
+{
+ public static final String COMPONENT_NAME = "facet";
+
+ @Override
+ public void prepare(ResponseBuilder rb) throws IOException
+ {
+ if (rb.req.getParams().getBool(FacetParams.FACET,false)) {
+ rb.setNeedDocSet( true );
+ rb.doFacets = true;
+ }
+ }
+
+ /**
+ * Actually run the query
+ * @param rb
+ */
+ @Override
+ public void process(ResponseBuilder rb) throws IOException
+ {
+ if (rb.doFacets) {
+ SolrParams params = rb.req.getParams();
+ SimpleFacets f = new SimpleFacets(rb.req,
+ rb.getResults().docSet,
+ params,
+ rb );
+
+ // TODO ???? add this directly to the response, or to the builder?
+ rb.rsp.add( "facet_counts", f.getFacetCounts() );
+ }
+ }
+
+ private static final String commandPrefix = "{!" + CommonParams.TERMS + "=$";
+
+ @Override
+ public int distributedProcess(ResponseBuilder rb) throws IOException {
+ if (!rb.doFacets) {
+ return ResponseBuilder.STAGE_DONE;
+ }
+
+ if (rb.stage == ResponseBuilder.STAGE_GET_FIELDS) {
+ // overlap facet refinement requests (those shards that we need a count for
+ // particular facet values from), where possible, with
+ // the requests to get fields (because we know that is the
+ // only other required phase).
+ // We do this in distributedProcess so we can look at all of the
+ // requests in the outgoing queue at once.
+
+
+
+ for (int shardNum=0; shardNum refinements = null;
+
+ for (DistribFieldFacet dff : rb._facetInfo.facets.values()) {
+ if (!dff.needRefinements) continue;
+ List refList = dff._toRefine[shardNum];
+ if (refList == null || refList.size()==0) continue;
+
+ String key = dff.getKey(); // reuse the same key that was used for the main facet
+ String termsKey = key + "__terms";
+ String termsVal = StrUtils.join(refList, ',');
+
+ String facetCommand;
+ // add terms into the original facet.field command
+ // do it via parameter reference to avoid another layer of encoding.
+
+ String termsKeyEncoded = QueryParsing.encodeLocalParamVal(termsKey);
+ if (dff.localParams != null) {
+ facetCommand = commandPrefix+termsKeyEncoded + " " + dff.facetStr.substring(2);
+ } else {
+ facetCommand = commandPrefix+termsKeyEncoded+'}'+dff.field;
+ }
+
+ if (refinements == null) {
+ refinements = new ArrayList();
+ }
+
+ refinements.add(facetCommand);
+ refinements.add(termsKey);
+ refinements.add(termsVal);
+ }
+
+ if (refinements == null) continue;
+
+
+ String shard = rb.shards[shardNum];
+ ShardRequest refine = null;
+ boolean newRequest = false;
+
+ // try to find a request that is already going out to that shard.
+ // If nshards becomes to great, we way want to move to hashing for better
+ // scalability.
+ for (ShardRequest sreq : rb.outgoing) {
+ if ((sreq.purpose & ShardRequest.PURPOSE_GET_FIELDS)!=0
+ && sreq.shards != null
+ && sreq.shards.length==1
+ && sreq.shards[0].equals(shard))
+ {
+ refine = sreq;
+ break;
+ }
+ }
+
+ if (refine == null) {
+ // we didn't find any other suitable requests going out to that shard, so
+ // create one ourselves.
+ newRequest = true;
+ refine = new ShardRequest();
+ refine.shards = new String[]{rb.shards[shardNum]};
+ refine.params = new ModifiableSolrParams(rb.req.getParams());
+ // don't request any documents
+ refine.params.remove(CommonParams.START);
+ refine.params.set(CommonParams.ROWS,"0");
+ }
+
+ refine.purpose |= ShardRequest.PURPOSE_REFINE_FACETS;
+ refine.params.set(FacetParams.FACET, "true");
+ refine.params.remove(FacetParams.FACET_FIELD);
+ refine.params.remove(FacetParams.FACET_QUERY);
+
+ for (int i=0; i 0) {
+ // set the initial limit higher to increase accuracy
+ dff.initialLimit = (int)(dff.initialLimit * 1.5) + 10;
+ dff.initialMincount = 0; // TODO: we could change this to 1, but would then need more refinement for small facet result sets?
+ } else {
+ // if limit==-1, then no need to artificially lower mincount to 0 if it's 1
+ dff.initialMincount = Math.min(dff.minCount, 1);
+ }
+ } else {
+ // we're sorting by index order.
+ // if minCount==0, we should always be able to get accurate results w/o over-requesting or refining
+ // if minCount==1, we should be able to get accurate results w/o over-requesting, but we'll need to refine
+ // if minCount==n (>1), we can set the initialMincount to minCount/nShards, rounded up.
+ // For example, we know that if minCount=10 and we have 3 shards, then at least one shard must have a count of 4 for the term
+ // For the minCount>1 case, we can generate too short of a list (miss terms at the end of the list) unless limit==-1
+ // For example: each shard could produce a list of top 10, but some of those could fail to make it into the combined list (i.e.
+ // we needed to go beyond the top 10 to generate the top 10 combined). Overrequesting can help a little here, but not as
+ // much as when sorting by count.
+ if (dff.minCount <= 1) {
+ dff.initialMincount = dff.minCount;
+ } else {
+ dff.initialMincount = (int)Math.ceil((double)dff.minCount / rb.shards.length);
+ // dff.initialMincount = 1;
+ }
+ }
+
+ if (dff.initialMincount != 0) {
+ sreq.params.set(paramStart + FacetParams.FACET_MINCOUNT, dff.initialMincount);
+ }
+
+ // Currently this is for testing only and allows overriding of the
+ // facet.limit set to the shards
+ dff.initialLimit = rb.req.getParams().getInt("facet.shard.limit", dff.initialLimit);
+
+ sreq.params.set(paramStart + FacetParams.FACET_LIMIT, dff.initialLimit);
+ }
+ } else {
+ // turn off faceting on other requests
+ sreq.params.set(FacetParams.FACET, "false");
+ // we could optionally remove faceting params
+ }
+ }
+
+ @Override
+ public void handleResponses(ResponseBuilder rb, ShardRequest sreq) {
+ if (!rb.doFacets) return;
+
+ if ((sreq.purpose & ShardRequest.PURPOSE_GET_FACETS)!=0) {
+ countFacets(rb, sreq);
+ } else if ((sreq.purpose & ShardRequest.PURPOSE_REFINE_FACETS)!=0) {
+ refineFacets(rb, sreq);
+ }
+ }
+
+
+
+
+ private void countFacets(ResponseBuilder rb, ShardRequest sreq) {
+ FacetInfo fi = rb._facetInfo;
+
+ for (ShardResponse srsp: sreq.responses) {
+ int shardNum = rb.getShardNum(srsp.getShard());
+ NamedList facet_counts = (NamedList)srsp.getSolrResponse().getResponse().get("facet_counts");
+
+ // handle facet queries
+ NamedList facet_queries = (NamedList)facet_counts.get("facet_queries");
+ if (facet_queries != null) {
+ for (int i=0; i> facet_dates =
+ (SimpleOrderedMap>)
+ facet_counts.get("facet_dates");
+
+ if (facet_dates != null) {
+
+ // go through each facet_date
+ for (Map.Entry> entry : facet_dates) {
+ final String field = entry.getKey();
+ if (fi.dateFacets.get(field) == null) {
+ // first time we've seen this field, no merging
+ fi.dateFacets.add(field, entry.getValue());
+
+ } else {
+ // not the first time, merge current field
+
+ SimpleOrderedMap