mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Add 'dspace-solr/' from commit 'bd02640bc5d871bd9da6bc73ff70a44ebbc659cf'
git-subtree-dir: dspace-solr git-subtree-mainline:53716c0f29
git-subtree-split:bd02640bc5
This commit is contained in:
14
dspace-solr/.gitattributes
vendored
Normal file
14
dspace-solr/.gitattributes
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
1
dspace-solr/.gitignore
vendored
Normal file
1
dspace-solr/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
target/
|
1
dspace-solr/.travis.yml
Normal file
1
dspace-solr/.travis.yml
Normal file
@@ -0,0 +1 @@
|
||||
language: java
|
40
dspace-solr/LICENSE
Normal file
40
dspace-solr/LICENSE
Normal file
@@ -0,0 +1,40 @@
|
||||
DSpace source code license:
|
||||
|
||||
|
||||
Copyright (c) 2002-2012, DuraSpace. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name DuraSpace nor the name of the DSpace Foundation
|
||||
nor the names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
|
||||
DSpace uses third-party libraries which may be distributed under
|
||||
different licenses to the above. Information about these licenses
|
||||
is detailed in the LICENSES_THIRD_PARTY file at the root of the source
|
||||
tree. You must agree to the terms of these licenses, in addition to
|
||||
the above DSpace source code license, in order to use this software.
|
5
dspace-solr/LICENSE_HEADER
Normal file
5
dspace-solr/LICENSE_HEADER
Normal file
@@ -0,0 +1,5 @@
|
||||
The contents of this file are subject to the license and copyright
|
||||
detailed in the LICENSE and NOTICE files at the root of the source
|
||||
tree and available online at
|
||||
|
||||
http://www.dspace.org/license/
|
15
dspace-solr/NOTICE
Normal file
15
dspace-solr/NOTICE
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
Licensing Notice
|
||||
|
||||
Fedora Commons joined with the DSpace Foundation and began operating under
|
||||
the new name DuraSpace in July 2009. DuraSpace holds the copyrights of
|
||||
the DSpace Foundation, Inc.
|
||||
|
||||
The DSpace Foundation, Inc. is a 501(c)3 corporation established in July 2007
|
||||
with a mission to promote and advance the dspace platform enabling management,
|
||||
access and preservation of digital works. The Foundation was able to transfer
|
||||
the legal copyright from Hewlett-Packard Company (HP) and Massachusetts
|
||||
Institute of Technology (MIT) to the DSpace Foundation in October 2007. Many
|
||||
of the files in the source code may contain a copyright statement stating HP
|
||||
and MIT possess the copyright, in these instances please note that the copy
|
||||
right has transferred to the DSpace foundation, and subsequently to DuraSpace.
|
14
dspace-solr/README
Normal file
14
dspace-solr/README
Normal file
@@ -0,0 +1,14 @@
|
||||
This is a special build of Apache Solr for DSpace (http://www.dspace.org).
|
||||
|
||||
This build is just a Maven WAR Overlay of the default Apache Solr Web application.
|
||||
This Overlay adds the following DSpace customizations:
|
||||
|
||||
* A new 'org.dspace.solr.filters.LocalHostRestrictionFilter' class (which restricts Solr access to localhost)
|
||||
* Customizes the default web.xml to utilize this new LocalHostRestrictionFilter
|
||||
|
||||
For more information about Maven WAR Overlays see:
|
||||
http://maven.apache.org/plugins/maven-war-plugin/overlays.html
|
||||
|
||||
This project has been created under an alternate groupId to
|
||||
be supported within the DSpace community and distributed
|
||||
within the the 'org.dspace' groupId.
|
252
dspace-solr/pom.xml
Normal file
252
dspace-solr/pom.xml
Normal file
@@ -0,0 +1,252 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-solr-parent</artifactId>
|
||||
<version>3.5.0.2-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Apache Solr Parent POM</name>
|
||||
<description>Apache Solr Parent POM</description>
|
||||
<url>http://lucene.apache.org/solr</url>
|
||||
|
||||
<organization>
|
||||
<name>DuraSpace</name>
|
||||
<url>http://www.dspace.org</url>
|
||||
</organization>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>7</version>
|
||||
<relativePath></relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- 'root.basedir' is the path to the root [dspace-src] dir. It must be redefined by each child POM,
|
||||
as it is used to reference the LICENSE_HEADER and *.properties file(s) in that directory. -->
|
||||
<root.basedir>${basedir}</root.basedir>
|
||||
</properties>
|
||||
|
||||
<inceptionYear>2006</inceptionYear>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache 2</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
</license>
|
||||
<license>
|
||||
<name>DuraSpace BSD License</name>
|
||||
<url>https://raw.github.com/DSpace/DSpace/master/LICENSE</url>
|
||||
<distribution>repo</distribution>
|
||||
<comments>
|
||||
A BSD 3-Clause license for the DSpace codebase.
|
||||
</comments>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<issueManagement>
|
||||
<system>JIRA</system>
|
||||
<url>https://jira.duraspace.org/browse/DS</url>
|
||||
</issueManagement>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:DSpace/dspace-solr.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:DSpace/dspace-solr.git</developerConnection>
|
||||
<url>git@github.com:DSpace/dspace-solr.git</url>
|
||||
</scm>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>DSpace Technical Users List</name>
|
||||
<subscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-tech
|
||||
</subscribe>
|
||||
<unsubscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-tech
|
||||
</unsubscribe>
|
||||
<post>dspace-tech AT lists.sourceforge.net</post>
|
||||
<archive>
|
||||
http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-tech
|
||||
</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>DSpace Developers List</name>
|
||||
<subscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-devel
|
||||
</subscribe>
|
||||
<unsubscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-devel
|
||||
</unsubscribe>
|
||||
<post>dspace-devel AT lists.sourceforge.net</post>
|
||||
<archive>
|
||||
http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-devel
|
||||
</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>DSpace General Issues List</name>
|
||||
<subscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-general
|
||||
</subscribe>
|
||||
<unsubscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-general
|
||||
</unsubscribe>
|
||||
<post>dspace-general AT lists.sourceforge.net</post>
|
||||
<archive>
|
||||
http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-general
|
||||
</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>DSpace SCM Commit Change-Log</name>
|
||||
<subscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-changelog
|
||||
</subscribe>
|
||||
<unsubscribe>
|
||||
http://lists.sourceforge.net/mailman/listinfo/dspace-changelog
|
||||
</unsubscribe>
|
||||
<post>noreply AT lists.sourceforge.net</post>
|
||||
<archive>
|
||||
http://sourceforge.net/mailarchive/forum.php?forum_name=dspace-changelog
|
||||
</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
|
||||
<developers>
|
||||
<!-- If you developed this, please fill in -->
|
||||
</developers>
|
||||
|
||||
<contributors>
|
||||
<contributor>
|
||||
<name>Add Your Name Here and submit a patch!</name>
|
||||
<email>contributor at myu.edu</email>
|
||||
<url>http://www.myu.edu/me</url>
|
||||
<organization>My University</organization>
|
||||
<organizationUrl>http://www.myu.edu</organizationUrl>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
<timezone>0</timezone>
|
||||
</contributor>
|
||||
</contributors>
|
||||
|
||||
<modules>
|
||||
<module>webapp</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.5.1</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.mycila.maven-license-plugin</groupId>
|
||||
<artifactId>maven-license-plugin</artifactId>
|
||||
<version>1.9.0</version>
|
||||
<configuration>
|
||||
<header>${root.basedir}/LICENSE_HEADER</header>
|
||||
<excludes>
|
||||
<exclude>src/main/*/org/apache/**</exclude>
|
||||
<exclude>**/web.xml</exclude>
|
||||
<exclude>**/src/test/resources/**</exclude>
|
||||
<exclude>**/META-INF/**</exclude>
|
||||
<exclude>**/robots.txt</exclude>
|
||||
<exclude>**/*.LICENSE</exclude>
|
||||
<exclude>**/LICENSE*</exclude>
|
||||
<exclude>**/README*</exclude>
|
||||
<exclude>**/NOTICE</exclude>
|
||||
<exclude>**/readme*</exclude>
|
||||
<exclude>**/.gitignore</exclude>
|
||||
</excludes>
|
||||
<mapping>
|
||||
<!-- Custom DSpace file extensions which are not recognized by maven-release-plugin:
|
||||
*.xmap, *.xslt, *.LICENSE -->
|
||||
<xmap>XML_STYLE</xmap>
|
||||
<xslt>XML_STYLE</xslt>
|
||||
<LICENSE>TEXT</LICENSE>
|
||||
</mapping>
|
||||
<properties />
|
||||
<encoding>UTF-8</encoding>
|
||||
<strictCheck>true</strictCheck>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
147
dspace-solr/webapp/pom.xml
Normal file
147
dspace-solr/webapp/pom.xml
Normal file
@@ -0,0 +1,147 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-solr-parent</artifactId>
|
||||
<version>3.5.0.2-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-solr</artifactId>
|
||||
<name>Apache Solr Webapp</name>
|
||||
<description>Apache Solr Server</description>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
<!-- 'root.basedir' is the path to the root [dspace-src] dir. It must be redefined by each child POM,
|
||||
as it is used to reference the LICENSE_HEADER and *.properties file(s) in that directory. -->
|
||||
<root.basedir>${basedir}/..</root.basedir>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<!-- This 'dspace-solr' WAR overlays the Apache Solr Web Application
|
||||
available in Maven Central -->
|
||||
<overlays>
|
||||
<overlay>
|
||||
<groupId>org.apache.solr</groupId>
|
||||
<artifactId>solr</artifactId>
|
||||
<!--
|
||||
Exclude the solr core named apache-solr-core, this is needed because the dspace-solr changes
|
||||
need to take precendence over the solr-core, the solr-core will still be loaded in the solr-core.jar
|
||||
-->
|
||||
<excludes>
|
||||
<exclude>WEB-INF/lib/apache-solr-core-3.5.0.jar</exclude>
|
||||
</excludes>
|
||||
</overlay>
|
||||
</overlays>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<!-- This execution creates a normal WAR (with all JARs, etc)-->
|
||||
<id>webapp</id>
|
||||
<configuration>
|
||||
<primaryArtifact>true</primaryArtifact>
|
||||
<archiveClasses>true</archiveClasses>
|
||||
<attachClasses>true</attachClasses>
|
||||
<classesClassifier>classes</classesClassifier>
|
||||
<warSourceExcludes>WEB-INF/classes/**</warSourceExcludes>
|
||||
<packagingExcludes>
|
||||
WEB-INF/classes/**,
|
||||
WEB-INF/lib/slf4j-jdk14-*.jar,
|
||||
WEB-INF/lib/log4j-over-slf4j-*.jar
|
||||
</packagingExcludes>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>war</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<!-- This execution creates a "skinny" WAR (without any JARs included)-->
|
||||
<id>skinny</id>
|
||||
<configuration>
|
||||
<primaryArtifact>false</primaryArtifact>
|
||||
<classifier>skinny</classifier>
|
||||
<warSourceExcludes>WEB-INF/lib/**,WEB-INF/classes/**</warSourceExcludes>
|
||||
<packagingExcludes>WEB-INF/lib/**,WEB-INF/classes/**</packagingExcludes>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>war</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- Depends on the Apache 'solr' web application (see Overlay settings above)-->
|
||||
<dependency>
|
||||
<groupId>org.apache.solr</groupId>
|
||||
<artifactId>solr</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.solr</groupId>
|
||||
<artifactId>solr-core</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.solr</groupId>
|
||||
<artifactId>solr-solrj</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Replace J.U.L. logging with log4j -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jul-to-slf4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>log4j</artifactId>
|
||||
<groupId>log4j</groupId>
|
||||
<type>jar</type>
|
||||
<version>1.2.16</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -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<rb.shards.length; shardNum++) {
|
||||
List<String> refinements = null;
|
||||
|
||||
for (DistribFieldFacet dff : rb._facetInfo.facets.values()) {
|
||||
if (!dff.needRefinements) continue;
|
||||
List<String> 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<String>();
|
||||
}
|
||||
|
||||
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<refinements.size();) {
|
||||
String facetCommand=refinements.get(i++);
|
||||
String termsKey=refinements.get(i++);
|
||||
String termsVal=refinements.get(i++);
|
||||
|
||||
refine.params.add(FacetParams.FACET_FIELD, facetCommand);
|
||||
refine.params.set(termsKey, termsVal);
|
||||
}
|
||||
|
||||
if (newRequest) {
|
||||
rb.addRequest(this, refine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseBuilder.STAGE_DONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest sreq) {
|
||||
if (!rb.doFacets) return;
|
||||
|
||||
if ((sreq.purpose & ShardRequest.PURPOSE_GET_TOP_IDS) != 0) {
|
||||
sreq.purpose |= ShardRequest.PURPOSE_GET_FACETS;
|
||||
|
||||
FacetInfo fi = rb._facetInfo;
|
||||
if (fi == null) {
|
||||
rb._facetInfo = fi = new FacetInfo();
|
||||
fi.parse(rb.req.getParams(), rb);
|
||||
// should already be true...
|
||||
// sreq.params.set(FacetParams.FACET, "true");
|
||||
}
|
||||
|
||||
sreq.params.remove(FacetParams.FACET_MINCOUNT);
|
||||
sreq.params.remove(FacetParams.FACET_OFFSET);
|
||||
sreq.params.remove(FacetParams.FACET_LIMIT);
|
||||
|
||||
for (DistribFieldFacet dff : fi.facets.values()) {
|
||||
String paramStart = "f." + dff.field + '.';
|
||||
sreq.params.remove(paramStart + FacetParams.FACET_MINCOUNT);
|
||||
sreq.params.remove(paramStart + FacetParams.FACET_OFFSET);
|
||||
|
||||
dff.initialLimit = dff.limit <= 0 ? dff.limit : dff.offset + dff.limit;
|
||||
|
||||
if (dff.sort.equals(FacetParams.FACET_SORT_COUNT)) {
|
||||
if (dff.limit > 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_queries.size(); i++) {
|
||||
String returnedKey = facet_queries.getName(i);
|
||||
long count = ((Number)facet_queries.getVal(i)).longValue();
|
||||
QueryFacet qf = fi.queryFacets.get(returnedKey);
|
||||
qf.count += count;
|
||||
}
|
||||
}
|
||||
|
||||
// step through each facet.field, adding results from this shard
|
||||
NamedList facet_fields = (NamedList)facet_counts.get("facet_fields");
|
||||
|
||||
if (facet_fields != null) {
|
||||
for (DistribFieldFacet dff : fi.facets.values()) {
|
||||
dff.add(shardNum, (NamedList)facet_fields.get(dff.getKey()), dff.initialLimit);
|
||||
}
|
||||
}
|
||||
|
||||
// Distributed facet_dates
|
||||
//
|
||||
// The implementation below uses the first encountered shard's
|
||||
// facet_dates as the basis for subsequent shards' data to be merged.
|
||||
// (the "NOW" param should ensure consistency)
|
||||
@SuppressWarnings("unchecked")
|
||||
SimpleOrderedMap<SimpleOrderedMap<Object>> facet_dates =
|
||||
(SimpleOrderedMap<SimpleOrderedMap<Object>>)
|
||||
facet_counts.get("facet_dates");
|
||||
|
||||
if (facet_dates != null) {
|
||||
|
||||
// go through each facet_date
|
||||
for (Map.Entry<String,SimpleOrderedMap<Object>> 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<Object> shardFieldValues
|
||||
= entry.getValue();
|
||||
SimpleOrderedMap<Object> existFieldValues
|
||||
= fi.dateFacets.get(field);
|
||||
|
||||
for (Map.Entry<String,Object> existPair : existFieldValues) {
|
||||
final String key = existPair.getKey();
|
||||
if (key.equals("gap") ||
|
||||
key.equals("end") ||
|
||||
key.equals("start")) {
|
||||
// we can skip these, must all be the same across shards
|
||||
continue;
|
||||
}
|
||||
// can be null if inconsistencies in shards responses
|
||||
Integer newValue = (Integer) shardFieldValues.get(key);
|
||||
if (null != newValue) {
|
||||
Integer oldValue = ((Integer) existPair.getValue());
|
||||
existPair.setValue(oldValue + newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Distributed facet_ranges
|
||||
//
|
||||
// The implementation below uses the first encountered shard's
|
||||
// facet_ranges as the basis for subsequent shards' data to be merged.
|
||||
@SuppressWarnings("unchecked")
|
||||
SimpleOrderedMap<SimpleOrderedMap<Object>> facet_ranges =
|
||||
(SimpleOrderedMap<SimpleOrderedMap<Object>>)
|
||||
facet_counts.get("facet_ranges");
|
||||
|
||||
if (facet_ranges != null) {
|
||||
|
||||
// go through each facet_range
|
||||
for (Map.Entry<String,SimpleOrderedMap<Object>> entry : facet_ranges) {
|
||||
final String field = entry.getKey();
|
||||
if (fi.rangeFacets.get(field) == null) {
|
||||
// first time we've seen this field, no merging
|
||||
fi.rangeFacets.add(field, entry.getValue());
|
||||
|
||||
} else {
|
||||
// not the first time, merge current field counts
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
NamedList<Integer> shardFieldValues
|
||||
= (NamedList<Integer>) entry.getValue().get("counts");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
NamedList<Integer> existFieldValues
|
||||
= (NamedList<Integer>) fi.rangeFacets.get(field).get("counts");
|
||||
|
||||
for (Map.Entry<String,Integer> existPair : existFieldValues) {
|
||||
final String key = existPair.getKey();
|
||||
// can be null if inconsistencies in shards responses
|
||||
Integer newValue = shardFieldValues.get(key);
|
||||
if (null != newValue) {
|
||||
Integer oldValue = existPair.getValue();
|
||||
existPair.setValue(oldValue + newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// This code currently assumes that there will be only a single
|
||||
// request ((with responses from all shards) sent out to get facets...
|
||||
// otherwise we would need to wait until all facet responses were received.
|
||||
//
|
||||
|
||||
for (DistribFieldFacet dff : fi.facets.values()) {
|
||||
// no need to check these facets for refinement
|
||||
if (dff.initialLimit <= 0 && dff.initialMincount == 0) continue;
|
||||
|
||||
// only other case where index-sort doesn't need refinement is if minCount==0
|
||||
if (dff.minCount == 0 && dff.sort.equals(FacetParams.FACET_SORT_INDEX)) continue;
|
||||
|
||||
@SuppressWarnings("unchecked") // generic array's are annoying
|
||||
List<String>[] tmp = (List<String>[]) new List[rb.shards.length];
|
||||
dff._toRefine = tmp;
|
||||
|
||||
ShardFacetCount[] counts = dff.getCountSorted();
|
||||
int ntop = Math.min(counts.length, dff.limit >= 0 ? dff.offset + dff.limit : Integer.MAX_VALUE);
|
||||
long smallestCount = counts.length == 0 ? 0 : counts[ntop-1].count;
|
||||
|
||||
for (int i=0; i<counts.length; i++) {
|
||||
ShardFacetCount sfc = counts[i];
|
||||
boolean needRefinement = false;
|
||||
|
||||
if (i<ntop) {
|
||||
// automatically flag the top values for refinement
|
||||
// this should always be true for facet.sort=index
|
||||
needRefinement = true;
|
||||
} else {
|
||||
// this logic should only be invoked for facet.sort=index (for now)
|
||||
|
||||
// calculate the maximum value that this term may have
|
||||
// and if it is >= smallestCount, then flag for refinement
|
||||
long maxCount = sfc.count;
|
||||
for (int shardNum=0; shardNum<rb.shards.length; shardNum++) {
|
||||
OpenBitSet obs = dff.counted[shardNum];
|
||||
if (!obs.get(sfc.termNum)) {
|
||||
// if missing from this shard, add the max it could be
|
||||
maxCount += dff.maxPossible(sfc,shardNum);
|
||||
}
|
||||
}
|
||||
if (maxCount >= smallestCount) {
|
||||
// TODO: on a tie, we could check the term values
|
||||
needRefinement = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needRefinement) {
|
||||
// add a query for each shard missing the term that needs refinement
|
||||
for (int shardNum=0; shardNum<rb.shards.length; shardNum++) {
|
||||
OpenBitSet obs = dff.counted[shardNum];
|
||||
if (!obs.get(sfc.termNum) && dff.maxPossible(sfc,shardNum)>0) {
|
||||
dff.needRefinements = true;
|
||||
List<String> lst = dff._toRefine[shardNum];
|
||||
if (lst == null) {
|
||||
lst = dff._toRefine[shardNum] = new ArrayList<String>();
|
||||
}
|
||||
lst.add(sfc.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void refineFacets(ResponseBuilder rb, ShardRequest sreq) {
|
||||
FacetInfo fi = rb._facetInfo;
|
||||
|
||||
for (ShardResponse srsp: sreq.responses) {
|
||||
// int shardNum = rb.getShardNum(srsp.shard);
|
||||
NamedList facet_counts = (NamedList)srsp.getSolrResponse().getResponse().get("facet_counts");
|
||||
NamedList facet_fields = (NamedList)facet_counts.get("facet_fields");
|
||||
|
||||
if (facet_fields == null) continue; // this can happen when there's an exception
|
||||
|
||||
for (int i=0; i<facet_fields.size(); i++) {
|
||||
String key = facet_fields.getName(i);
|
||||
DistribFieldFacet dff = fi.facets.get(key);
|
||||
if (dff == null) continue;
|
||||
|
||||
NamedList shardCounts = (NamedList)facet_fields.getVal(i);
|
||||
|
||||
for (int j=0; j<shardCounts.size(); j++) {
|
||||
String name = shardCounts.getName(j);
|
||||
long count = ((Number)shardCounts.getVal(j)).longValue();
|
||||
ShardFacetCount sfc = dff.counts.get(name);
|
||||
sfc.count += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishStage(ResponseBuilder rb) {
|
||||
if (!rb.doFacets || rb.stage != ResponseBuilder.STAGE_GET_FIELDS) return;
|
||||
// wait until STAGE_GET_FIELDS
|
||||
// so that "result" is already stored in the response (for aesthetics)
|
||||
|
||||
|
||||
FacetInfo fi = rb._facetInfo;
|
||||
|
||||
NamedList<Object> facet_counts = new SimpleOrderedMap<Object>();
|
||||
|
||||
NamedList facet_queries = new SimpleOrderedMap();
|
||||
facet_counts.add("facet_queries",facet_queries);
|
||||
for (QueryFacet qf : fi.queryFacets.values()) {
|
||||
facet_queries.add(qf.getKey(), num(qf.count));
|
||||
}
|
||||
|
||||
NamedList<Object> facet_fields = new SimpleOrderedMap<Object>();
|
||||
facet_counts.add("facet_fields", facet_fields);
|
||||
|
||||
for (DistribFieldFacet dff : fi.facets.values()) {
|
||||
NamedList<Object> fieldCounts = new NamedList<Object>(); // order is more important for facets
|
||||
facet_fields.add(dff.getKey(), fieldCounts);
|
||||
|
||||
ShardFacetCount[] counts;
|
||||
boolean countSorted = dff.sort.equals(FacetParams.FACET_SORT_COUNT);
|
||||
if (countSorted) {
|
||||
counts = dff.countSorted;
|
||||
if (counts == null || dff.needRefinements) {
|
||||
counts = dff.getCountSorted();
|
||||
}
|
||||
} else if (dff.sort.equals(FacetParams.FACET_SORT_INDEX)) {
|
||||
counts = dff.getLexSorted();
|
||||
} else { // TODO: log error or throw exception?
|
||||
counts = dff.getLexSorted();
|
||||
}
|
||||
|
||||
if (countSorted) {
|
||||
int end = dff.limit < 0 ? counts.length : Math.min(dff.offset + dff.limit, counts.length);
|
||||
for (int i=dff.offset; i<end; i++) {
|
||||
if (counts[i].count < dff.minCount) {
|
||||
break;
|
||||
}
|
||||
fieldCounts.add(counts[i].name, num(counts[i].count));
|
||||
}
|
||||
} else {
|
||||
int off = dff.offset;
|
||||
int lim = dff.limit >= 0 ? dff.limit : Integer.MAX_VALUE;
|
||||
|
||||
// index order...
|
||||
for (int i=0; i<counts.length; i++) {
|
||||
long count = counts[i].count;
|
||||
if (count < dff.minCount) continue;
|
||||
if (off > 0) {
|
||||
off--;
|
||||
continue;
|
||||
}
|
||||
if (lim <= 0) {
|
||||
break;
|
||||
}
|
||||
lim--;
|
||||
fieldCounts.add(counts[i].name, num(count));
|
||||
}
|
||||
}
|
||||
|
||||
if (dff.missing) {
|
||||
fieldCounts.add(null, num(dff.missingCount));
|
||||
}
|
||||
}
|
||||
|
||||
facet_counts.add("facet_dates", fi.dateFacets);
|
||||
facet_counts.add("facet_ranges", fi.rangeFacets);
|
||||
|
||||
rb.rsp.add("facet_counts", facet_counts);
|
||||
|
||||
rb._facetInfo = null; // could be big, so release asap
|
||||
}
|
||||
|
||||
|
||||
// use <int> tags for smaller facet counts (better back compatibility)
|
||||
private Number num(long val) {
|
||||
if (val < Integer.MAX_VALUE) return (int)val;
|
||||
else return val;
|
||||
}
|
||||
private Number num(Long val) {
|
||||
if (val.longValue() < Integer.MAX_VALUE) return val.intValue();
|
||||
else return val;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
/// SolrInfoMBean
|
||||
////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Handle Faceting";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "$Revision: 1152531 $";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceId() {
|
||||
return "$Id: FacetComponent.java 1152531 2011-07-31 00:43:33Z koji $";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSource() {
|
||||
return "$URL: http://svn.apache.org/repos/asf/lucene/dev/tags/lucene_solr_3_5_0/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java $";
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL[] getDocs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>This API is experimental and subject to change</b>
|
||||
*/
|
||||
public static class FacetInfo {
|
||||
public LinkedHashMap<String,QueryFacet> queryFacets;
|
||||
public LinkedHashMap<String,DistribFieldFacet> facets;
|
||||
public SimpleOrderedMap<SimpleOrderedMap<Object>> dateFacets
|
||||
= new SimpleOrderedMap<SimpleOrderedMap<Object>>();
|
||||
public SimpleOrderedMap<SimpleOrderedMap<Object>> rangeFacets
|
||||
= new SimpleOrderedMap<SimpleOrderedMap<Object>>();
|
||||
|
||||
public List exceptionList;
|
||||
|
||||
void parse(SolrParams params, ResponseBuilder rb) {
|
||||
queryFacets = new LinkedHashMap<String,QueryFacet>();
|
||||
facets = new LinkedHashMap<String,DistribFieldFacet>();
|
||||
|
||||
String[] facetQs = params.getParams(FacetParams.FACET_QUERY);
|
||||
if (facetQs != null) {
|
||||
for (String query : facetQs) {
|
||||
QueryFacet queryFacet = new QueryFacet(rb, query);
|
||||
queryFacets.put(queryFacet.getKey(), queryFacet);
|
||||
}
|
||||
}
|
||||
|
||||
String[] facetFs = params.getParams(FacetParams.FACET_FIELD);
|
||||
if (facetFs != null) {
|
||||
|
||||
for (String field : facetFs) {
|
||||
DistribFieldFacet ff = new DistribFieldFacet(rb, field);
|
||||
facets.put(ff.getKey(), ff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>This API is experimental and subject to change</b>
|
||||
*/
|
||||
public static class FacetBase {
|
||||
String facetType; // facet.field, facet.query, etc (make enum?)
|
||||
String facetStr; // original parameter value of facetStr
|
||||
String facetOn; // the field or query, absent localParams if appropriate
|
||||
private String key; // label in the response for the result... "foo" for {!key=foo}myfield
|
||||
SolrParams localParams; // any local params for the facet
|
||||
|
||||
public FacetBase(ResponseBuilder rb, String facetType, String facetStr) {
|
||||
this.facetType = facetType;
|
||||
this.facetStr = facetStr;
|
||||
try {
|
||||
this.localParams = QueryParsing.getLocalParams(facetStr, rb.req.getParams());
|
||||
} catch (ParseException e) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
|
||||
}
|
||||
this.facetOn = facetStr;
|
||||
this.key = facetStr;
|
||||
|
||||
if (localParams != null) {
|
||||
// remove local params unless it's a query
|
||||
if (!facetType.equals(FacetParams.FACET_QUERY)) {
|
||||
facetOn = localParams.get(CommonParams.VALUE);
|
||||
key = facetOn;
|
||||
}
|
||||
|
||||
key = localParams.get(CommonParams.OUTPUT_KEY, key);
|
||||
}
|
||||
}
|
||||
|
||||
/** returns the key in the response that this facet will be under */
|
||||
public String getKey() { return key; }
|
||||
public String getType() { return facetType; }
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>This API is experimental and subject to change</b>
|
||||
*/
|
||||
public static class QueryFacet extends FacetBase {
|
||||
public long count;
|
||||
|
||||
public QueryFacet(ResponseBuilder rb, String facetStr) {
|
||||
super(rb, FacetParams.FACET_QUERY, facetStr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>This API is experimental and subject to change</b>
|
||||
*/
|
||||
public static class FieldFacet extends FacetBase {
|
||||
public String field; // the field to facet on... "myfield" for {!key=foo}myfield
|
||||
public FieldType ftype;
|
||||
public int offset;
|
||||
public int limit;
|
||||
public int minCount;
|
||||
public String sort;
|
||||
public boolean missing;
|
||||
public String prefix;
|
||||
public long missingCount;
|
||||
|
||||
public FieldFacet(ResponseBuilder rb, String facetStr) {
|
||||
super(rb, FacetParams.FACET_FIELD, facetStr);
|
||||
fillParams(rb, rb.req.getParams(), facetOn);
|
||||
}
|
||||
|
||||
private void fillParams(ResponseBuilder rb, SolrParams params, String field) {
|
||||
this.field = field;
|
||||
this.ftype = rb.req.getSchema().getFieldTypeNoEx(this.field);
|
||||
this.offset = params.getFieldInt(field, FacetParams.FACET_OFFSET, 0);
|
||||
this.limit = params.getFieldInt(field, FacetParams.FACET_LIMIT, 100);
|
||||
Integer mincount = params.getFieldInt(field, FacetParams.FACET_MINCOUNT);
|
||||
if (mincount==null) {
|
||||
Boolean zeros = params.getFieldBool(field, FacetParams.FACET_ZEROS);
|
||||
// mincount = (zeros!=null && zeros) ? 0 : 1;
|
||||
mincount = (zeros!=null && !zeros) ? 1 : 0;
|
||||
// current default is to include zeros.
|
||||
}
|
||||
this.minCount = mincount;
|
||||
this.missing = params.getFieldBool(field, FacetParams.FACET_MISSING, false);
|
||||
// default to sorting by count if there is a limit.
|
||||
this.sort = params.getFieldParam(field, FacetParams.FACET_SORT, limit>0 ? FacetParams.FACET_SORT_COUNT : FacetParams.FACET_SORT_INDEX);
|
||||
if (this.sort.equals(FacetParams.FACET_SORT_COUNT_LEGACY)) {
|
||||
this.sort = FacetParams.FACET_SORT_COUNT;
|
||||
} else if (this.sort.equals(FacetParams.FACET_SORT_INDEX_LEGACY)) {
|
||||
this.sort = FacetParams.FACET_SORT_INDEX;
|
||||
}
|
||||
this.prefix = params.getFieldParam(field,FacetParams.FACET_PREFIX);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>This API is experimental and subject to change</b>
|
||||
*/
|
||||
public static class DistribFieldFacet extends FieldFacet {
|
||||
public List<String>[] _toRefine; // a List<String> of refinements needed, one for each shard.
|
||||
|
||||
// SchemaField sf; // currently unneeded
|
||||
|
||||
// the max possible count for a term appearing on no list
|
||||
public long missingMaxPossible;
|
||||
// the max possible count for a missing term for each shard (indexed by shardNum)
|
||||
public long[] missingMax;
|
||||
public OpenBitSet[] counted; // a bitset for each shard, keeping track of which terms seen
|
||||
public HashMap<String,ShardFacetCount> counts = new HashMap<String,ShardFacetCount>(128);
|
||||
public int termNum;
|
||||
|
||||
public int initialLimit; // how many terms requested in first phase
|
||||
public int initialMincount; // mincount param sent to each shard
|
||||
public boolean needRefinements;
|
||||
public ShardFacetCount[] countSorted;
|
||||
|
||||
DistribFieldFacet(ResponseBuilder rb, String facetStr) {
|
||||
super(rb, facetStr);
|
||||
// sf = rb.req.getSchema().getField(field);
|
||||
missingMax = new long[rb.shards.length];
|
||||
counted = new OpenBitSet[rb.shards.length];
|
||||
}
|
||||
|
||||
void add(int shardNum, NamedList shardCounts, int numRequested) {
|
||||
// shardCounts could be null if there was an exception
|
||||
int sz = shardCounts == null ? 0 : shardCounts.size();
|
||||
int numReceived = sz;
|
||||
|
||||
OpenBitSet terms = new OpenBitSet(termNum+sz);
|
||||
|
||||
long last = 0;
|
||||
for (int i=0; i<sz; i++) {
|
||||
String name = shardCounts.getName(i);
|
||||
long count = ((Number)shardCounts.getVal(i)).longValue();
|
||||
if (name == null) {
|
||||
missingCount += count;
|
||||
numReceived--;
|
||||
} else {
|
||||
ShardFacetCount sfc = counts.get(name);
|
||||
if (sfc == null) {
|
||||
sfc = new ShardFacetCount();
|
||||
sfc.name = name;
|
||||
sfc.indexed = ftype == null ? sfc.name : ftype.toInternal(sfc.name);
|
||||
sfc.termNum = termNum++;
|
||||
counts.put(name, sfc);
|
||||
}
|
||||
sfc.count += count;
|
||||
terms.fastSet(sfc.termNum);
|
||||
last = count;
|
||||
}
|
||||
}
|
||||
|
||||
// the largest possible missing term is initialMincount if we received less
|
||||
// than the number requested.
|
||||
if (numRequested<0 || numRequested != 0 && numReceived < numRequested) {
|
||||
last = initialMincount;
|
||||
}
|
||||
|
||||
missingMaxPossible += last;
|
||||
missingMax[shardNum] = last;
|
||||
counted[shardNum] = terms;
|
||||
}
|
||||
|
||||
public ShardFacetCount[] getLexSorted() {
|
||||
ShardFacetCount[] arr = counts.values().toArray(new ShardFacetCount[counts.size()]);
|
||||
Arrays.sort(arr, new Comparator<ShardFacetCount>() {
|
||||
public int compare(ShardFacetCount o1, ShardFacetCount o2) {
|
||||
return o1.indexed.compareTo(o2.indexed);
|
||||
}
|
||||
});
|
||||
countSorted = arr;
|
||||
return arr;
|
||||
}
|
||||
|
||||
public ShardFacetCount[] getCountSorted() {
|
||||
ShardFacetCount[] arr = counts.values().toArray(new ShardFacetCount[counts.size()]);
|
||||
Arrays.sort(arr, new Comparator<ShardFacetCount>() {
|
||||
public int compare(ShardFacetCount o1, ShardFacetCount o2) {
|
||||
if (o2.count < o1.count) return -1;
|
||||
else if (o1.count < o2.count) return 1;
|
||||
return o1.indexed.compareTo(o2.indexed);
|
||||
}
|
||||
});
|
||||
countSorted = arr;
|
||||
return arr;
|
||||
}
|
||||
|
||||
// returns the max possible value this ShardFacetCount could have for this shard
|
||||
// (assumes the shard did not report a count for this value)
|
||||
long maxPossible(ShardFacetCount sfc, int shardNum) {
|
||||
return missingMax[shardNum];
|
||||
// TODO: could store the last term in the shard to tell if this term
|
||||
// comes before or after it. If it comes before, we could subtract 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>This API is experimental and subject to change</b>
|
||||
*/
|
||||
public static class ShardFacetCount {
|
||||
public String name;
|
||||
public String indexed; // the indexed form of the name... used for comparisons.
|
||||
public long count;
|
||||
public int termNum; // term number starting at 0 (used in bit arrays)
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{term="+name+",termNum="+termNum+",count="+count+"}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
|
||||
package org.dspace.solr.filters;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import org.apache.log4j.Hierarchy;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
import org.apache.log4j.helpers.Loader;
|
||||
import org.apache.log4j.spi.Configurator;
|
||||
import org.apache.log4j.spi.RootLogger;
|
||||
import org.apache.log4j.xml.DOMConfigurator;
|
||||
|
||||
/**
|
||||
* Initialize Log4J at application startup.
|
||||
* This class mimics the default Log4J initialization procedure, except
|
||||
* that it is controlled by context parameters rather than system properties.
|
||||
*
|
||||
* @author Mark H. Wood
|
||||
*/
|
||||
public class ConfigureLog4jListener
|
||||
implements ServletContextListener
|
||||
{
|
||||
public void contextInitialized(ServletContextEvent sce)
|
||||
{
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
|
||||
String logConfig = ctx.getInitParameter("log4j.configuration");
|
||||
if (null == logConfig)
|
||||
logConfig = "log4j.properties";
|
||||
|
||||
URL configURL;
|
||||
try {
|
||||
configURL = new URL(logConfig);
|
||||
} catch (MalformedURLException e) {
|
||||
configURL = Loader.getResource(logConfig);
|
||||
}
|
||||
|
||||
if (null == configURL)
|
||||
{
|
||||
ctx.log("Log4J configuration not found. Left unconfigured.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.log(" In context " + ctx.getContextPath() +
|
||||
", configuring Log4J from " + configURL.toExternalForm());
|
||||
|
||||
String configuratorName = ctx.getInitParameter("log4j.configuratorClass");
|
||||
if (null != configuratorName)
|
||||
{
|
||||
Configurator configurator;
|
||||
try
|
||||
{
|
||||
configurator = (Configurator) Class.forName(configuratorName).newInstance();
|
||||
} catch (Exception ex)
|
||||
{
|
||||
ctx.log("Unable to load custom Log4J configuration class '"
|
||||
+ configuratorName + "': " + ex.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
configurator.doConfigure(configURL, new Hierarchy(new RootLogger(Level.OFF)));
|
||||
}
|
||||
else if (configURL.getFile().endsWith(".xml"))
|
||||
DOMConfigurator.configure(configURL);
|
||||
else
|
||||
PropertyConfigurator.configure(configURL);
|
||||
}
|
||||
}
|
||||
|
||||
public void contextDestroyed(ServletContextEvent sce)
|
||||
{
|
||||
// Nothing to be done
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.solr.filters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class LocalHostRestrictionFilter implements Filter {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
public LocalHostRestrictionFilter() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
if(enabled){
|
||||
InetAddress ia = InetAddress.getLocalHost();
|
||||
String localAddr = ia.getHostAddress();
|
||||
String remoteAddr = request.getRemoteAddr();
|
||||
|
||||
if(!(localAddr.equals(remoteAddr) || remoteAddr.equals("127.0.0.1") || remoteAddr.startsWith("0:0:0:0:0:0:0:1")))
|
||||
{
|
||||
((HttpServletResponse)response).sendError(403);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void init(FilterConfig arg0) throws ServletException {
|
||||
String restrict = arg0.getServletContext().getInitParameter("LocalHostRestrictionFilter.localhost");
|
||||
if("false".equalsIgnoreCase(restrict))
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
181
dspace-solr/webapp/src/main/webapp/WEB-INF/web.xml
Normal file
181
dspace-solr/webapp/src/main/webapp/WEB-INF/web.xml
Normal file
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<web-app>
|
||||
|
||||
<!-- Uncomment if you are trying to use a Resin version before 3.0.19.
|
||||
Their XML implementation isn't entirely compatible with Xerces.
|
||||
Below are the implementations to use with Sun's JVM.
|
||||
<system-property javax.xml.xpath.XPathFactory=
|
||||
"com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl"/>
|
||||
<system-property javax.xml.parsers.DocumentBuilderFactory=
|
||||
"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"/>
|
||||
<system-property javax.xml.parsers.SAXParserFactory=
|
||||
"com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"/>
|
||||
-->
|
||||
|
||||
<!-- People who want to hardcode their "Solr Home" directly into the
|
||||
WAR File can set the JNDI property here...
|
||||
-->
|
||||
<!--
|
||||
<env-entry>
|
||||
<env-entry-name>solr/home</env-entry-name>
|
||||
<env-entry-value>/put/your/solr/home/here</env-entry-value>
|
||||
<env-entry-type>java.lang.String</env-entry-type>
|
||||
</env-entry>
|
||||
-->
|
||||
|
||||
<context-param>
|
||||
<param-name>log4j.configuration</param-name>
|
||||
<param-value>file://${dspace.dir}/config/log4j.properties</param-value>
|
||||
<description>URL locating a Log4J configuration file (properties or XML).</description>
|
||||
</context-param>
|
||||
|
||||
<!-- Any path (name) registered in solrconfig.xml will be sent to that filter -->
|
||||
<filter>
|
||||
<filter-name>LocalHostRestrictionFilter</filter-name>
|
||||
<filter-class>org.dspace.solr.filters.LocalHostRestrictionFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<!--
|
||||
Any path (name) registered in solrconfig.xml will be sent to that
|
||||
filter
|
||||
-->
|
||||
<filter>
|
||||
<filter-name>SolrRequestFilter</filter-name>
|
||||
<filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>
|
||||
<!-- If you are wiring Solr into a larger web application which controls
|
||||
the web context root, you will probably want to mount Solr under
|
||||
a path prefix (app.war with /app/solr mounted into it, for example).
|
||||
You will need to put this prefix in front of the SolrDispatchFilter
|
||||
url-pattern mapping too (/solr/*), and also on any paths for
|
||||
legacy Solr servlet mappings you may be using.
|
||||
For the admin JSP's to work properly in a path-prefixed configuration,
|
||||
the admin folder containing the JSPs needs to be under the app context root
|
||||
named to match the path-prefix. For example:
|
||||
|
||||
.war
|
||||
xxx
|
||||
admin
|
||||
stats.jsp
|
||||
-->
|
||||
<!--
|
||||
<init-param>
|
||||
<param-name>path-prefix</param-name>
|
||||
<param-value>/xxx</param-value>
|
||||
</init-param>
|
||||
-->
|
||||
</filter>
|
||||
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>LocalHostRestrictionFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<!--
|
||||
NOTE: When using multicore, /admin JSP URLs with a core specified
|
||||
such as /solr/coreName/admin/stats.jsp get forwarded by a
|
||||
RequestDispatcher to /solr/admin/stats.jsp with the specified core
|
||||
put into request scope keyed as "org.apache.solr.SolrCore".
|
||||
|
||||
It is unnecessary, and potentially problematic, to have the SolrDispatchFilter
|
||||
configured to also filter on forwards. Do not configure
|
||||
this dispatcher as <dispatcher>FORWARD</dispatcher>.
|
||||
-->
|
||||
<filter-name>SolrRequestFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- Otherwise it will continue to the old servlets -->
|
||||
|
||||
<listener>
|
||||
<listener-class>org.dspace.solr.filters.ConfigureLog4jListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>SolrServer</servlet-name>
|
||||
<display-name>Solr</display-name>
|
||||
<description>Solr Server</description>
|
||||
<servlet-class>org.apache.solr.servlet.SolrServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>SolrUpdate</servlet-name>
|
||||
<display-name>SolrUpdate</display-name>
|
||||
<description>Solr Update Handler</description>
|
||||
<servlet-class>org.apache.solr.servlet.SolrUpdateServlet</servlet-class>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Logging</servlet-name>
|
||||
<servlet-class>org.apache.solr.servlet.LogLevelSelection</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<!-- @Deprecated -->
|
||||
<servlet>
|
||||
<servlet-name>ping</servlet-name>
|
||||
<jsp-file>/admin/ping.jsp</jsp-file>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>SolrServer</servlet-name>
|
||||
<url-pattern>/select/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>SolrUpdate</servlet-name>
|
||||
<url-pattern>/update/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Logging</servlet-name>
|
||||
<url-pattern>/admin/logging</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- @Deprecated -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>ping</servlet-name>
|
||||
<url-pattern>/admin/ping</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- @Deprecated -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>Logging</servlet-name>
|
||||
<url-pattern>/admin/logging.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<mime-mapping>
|
||||
<extension>.xsl</extension>
|
||||
<!-- per http://www.w3.org/TR/2006/PR-xslt20-20061121/ -->
|
||||
<mime-type>application/xslt+xml</mime-type>
|
||||
</mime-mapping>
|
||||
<!-- People who want to hardcode their "Solr Home" directly into the
|
||||
WAR File can set the JNDI property here...
|
||||
-->
|
||||
<env-entry>
|
||||
<env-entry-name>solr/home</env-entry-name>
|
||||
<env-entry-value>${dspace.dir}/solr</env-entry-value>
|
||||
<env-entry-type>java.lang.String</env-entry-type>
|
||||
</env-entry>
|
||||
|
||||
</web-app>
|
Reference in New Issue
Block a user