Author: ivol37 at gmail.com
Date: Tue Jan 25 17:27:49 2011
New Revision: 707
Log:
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrRestService.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/NutchIndex.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApi.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/default_schema.xml
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/default_solrconfig.xml
Removed:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrCoreProvider.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf_core_profile/schema.xml
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/conf_core_profile/solrconfig.xml
Modified:
sandbox/ivol/amdatu-searchandindex/solr/pom.xml
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
Modified: sandbox/ivol/amdatu-searchandindex/solr/pom.xml
==============================================================================
--- sandbox/ivol/amdatu-searchandindex/solr/pom.xml (original)
+++ sandbox/ivol/amdatu-searchandindex/solr/pom.xml Tue Jan 25 17:27:49 2011
@@ -88,7 +88,37 @@
<scope>provided</scope>
<type>bundle</type>
</dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <artifactId>solr-solrj</artifactId>
+ <groupId>org.apache.solr</groupId>
+ <version>1.4.0</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nutch</groupId>
+ <artifactId>nutch</artifactId>
+ <version>2.0-dev</version>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
+
+
+
+ <repositories>
+ <repository>
+ <id>apacherepo</id>
+ <name>Apache Repository</name>
+ <url>https://repository.apache.org/content/groups/public</url>
+ </repository>
+ </repositories>
+
<build>
<plugins>
<plugin>
@@ -102,7 +132,7 @@
<Embed-Dependency>*;scope=compile</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
<Import-Package>
- !org.mortbay.*,,
+ !org.mortbay.*,
!com.sun.*,
!javax.mail.*,
!javax.jmdns,
@@ -113,6 +143,7 @@
!com.ibm.*,
!org.apache.avalon.*,
!org.apache.log,
+ org.codehaus.stax2.*,
*
</Import-Package>
<Export-Package>
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrRestService.java
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/SolrRestService.java
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,5 @@
+package org.amdatu.searchandindex.solr;
+
+public interface SolrRestService {
+
+}
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/NutchIndex.java
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/NutchIndex.java
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,5 @@
+package org.amdatu.searchandindex.solr.impl;
+
+public class NutchIndex {
+
+}
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApi.java
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrApi.java
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.searchandindex.solr.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+
+import org.amdatu.core.config.templates.ConfigTemplateManager;
+import org.amdatu.core.tenant.Tenant;
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.CoreDescriptor;
+import org.apache.solr.core.NakamuraSolrConfig;
+import org.apache.solr.core.NakamuraSolrResourceLoader;
+import org.apache.solr.core.SolrConfig;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.schema.IndexSchema;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.xml.sax.SAXException;
+
+public class SolrApi {
+ // Statics
+ private static final String DEFAULT_SCHEMA = "default_schema.xml";
+ private static final String DEFAULT_SOLRCONFIG = "default_solrconfig.xml";
+
+ // Service dependencies injected by the dependency manager
+ private volatile LogService m_logService;
+ private volatile BundleContext m_bundleContext;
+ private volatile ConfigTemplateManager m_configTemplateManager;
+
+ // Private members
+ private File m_workDir;
+ private CoreContainer m_coreContainer;
+
+ public SolrApi(File workDir, CoreContainer coreContainer) {
+ m_workDir = workDir;
+ m_coreContainer = coreContainer;
+ }
+
+ public void createIndex(Tenant tenant, String index) {
+ // Verify if a core for this index already exists
+ String coreDirName = tenant.getId() + "/" + index;
+ String coreName = tenant.getId() + "_" + index;
+ if (m_coreContainer.getCore(coreName) == null) {
+ try {
+ m_logService.log(LogService.LOG_INFO, "Creating new Solr index
'" + index + "' for tenant '" + tenant.getId() + "'");
+
+ // Create a new core. The name of that core will be <tenant
id>/<index name>
+ createCore(coreName, coreDirName);
+ }
+ catch (IOException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create Solr
core configuration for '" + coreName + "'", e);
+ }
+ catch (ParserConfigurationException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create Solr
core configuration for '" + coreName + "'", e);
+ }
+ catch (SAXException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create Solr
core configuration for '" + coreName + "'", e);
+ }
+ } else {
+ m_logService.log(LogService.LOG_INFO, "Solr index '" + index + "'
for tenant '" + tenant.getId() + "' not created since it already exists");
+ }
+ }
+
+ public void updateIndex(Tenant tenant, String index, InputStream is)
throws XMLStreamException, SolrServerException, IOException {
+ String coreName = tenant.getId() + "_" + index;
+ SolrServer server = new EmbeddedSolrServer(m_coreContainer, coreName);
+ SolrInputDocument solrDocument = SolrUtil.fromXMLStream(is);
+ server.add(solrDocument);
+ }
+
+ private void createCore(String coreName, String coreDirName) throws
IOException, ParserConfigurationException, SAXException {
+ // Save the current context classloader
+ final ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
+ try {
+ // Classloader switcheroo
+ final ClassLoader classLoader = this.getClass().getClassLoader();
+ Thread.currentThread().setContextClassLoader(classLoader);
+
+ // Prepare /conf directory for this core
+ File coreDir = new File(m_workDir, coreDirName);
+ File coreConfDir = new File(m_workDir, coreDirName + "/conf");
+ if (coreConfDir.exists()) {
+ coreConfDir.delete();
+ }
+ coreConfDir.mkdirs();
+ File coresConfigFile = new File(m_workDir,
SolrDaemonServiceImpl.SOLR_CONFIG_XML);
+
+ Bundle bundle = m_bundleContext.getBundle();
+
+ // Write the schema
+ URL schema = bundle.getResource(DEFAULT_SCHEMA);
+ File targetSchema = new File(m_workDir + "/" + coreDirName +
"/conf/schema.xml");
+ m_configTemplateManager.writeConfiguration(schema, targetSchema);
+
+ // Write the solrConfig
+ URL solrConfig = bundle.getResource(DEFAULT_SOLRCONFIG);
+ File targetSolrConfig = new File(m_workDir + "/" + coreDirName +
"/conf/solrconfig.xml");
+ m_configTemplateManager.writeConfiguration(solrConfig,
targetSolrConfig);
+
+ SolrResourceLoader loader = new
NakamuraSolrResourceLoader(m_workDir.getAbsolutePath(), classLoader);
+ SolrConfig config = new NakamuraSolrConfig(loader,
"solrconfig.xml", new FileInputStream(targetSolrConfig));
+ IndexSchema indexSchema = new IndexSchema(config, null, new
FileInputStream(targetSchema));
+ CoreDescriptor desc = new CoreDescriptor(m_coreContainer,
coreName, coreDir.getAbsolutePath());
+ SolrCore nakamuraCore = new SolrCore(coreName,
coreDir.getAbsolutePath(), config, indexSchema, desc);
+ m_coreContainer.register(coreName, nakamuraCore, false);
+ m_coreContainer.persistFile(coresConfigFile);
+ } finally {
+ // Restore classloader
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+}
Modified:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
==============================================================================
---
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
(original)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrDaemonServiceImpl.java
Tue Jan 25 17:27:49 2011
@@ -21,25 +21,20 @@
import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
-import java.util.List;
import org.amdatu.core.config.templates.ConfigTemplateManager;
-import org.amdatu.core.tenant.Tenant;
import org.amdatu.core.tenant.TenantManagementService;
-import org.amdatu.searchandindex.solr.SolrCoreProvider;
+import org.amdatu.searchandindex.solr.SolrRestService;
import org.amdatu.searchandindex.solr.SolrService;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
import org.amdatu.web.httpcontext.ResourceProvider;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.ServiceDependency;
import org.apache.solr.core.CoreContainer;
-import org.apache.solr.core.NakamuraSolrResourceLoader;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.core.SolrResourceLoader;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.log.LogService;
@@ -49,21 +44,18 @@
*/
public class SolrDaemonServiceImpl implements SolrService, ManagedService {
// Statics
- private static final String SOLR_CONFIG_XML = "solr.xml";
+ public static final String SOLR_CONFIG_XML = "solr.xml";
private static final String CONFIG_DIR = "conf";
// Services injected by the Felix dependency manager
private volatile LogService m_logService;
private volatile BundleContext m_bundleContext;
private volatile DependencyManager m_dependencyManager;
- private volatile TenantManagementService m_tenantService;
private volatile ConfigTemplateManager m_configTemplateManager;
// Private members
private CoreContainer m_coreContainer;
-
private File m_workDir;
- private List<Tenant> m_tenants;
/**
* The init() method is invoked by the Felix dependency manager.
@@ -77,36 +69,37 @@
// Load the URL of the storage-conf.xml and write it file using
the config template
// manager, which automatically replaces configuration entries in
that file
File storageConfigFile = new File(m_workDir, SOLR_CONFIG_XML);
- m_workDir.mkdirs();
- Bundle bundle = m_bundleContext.getBundle();
- URL url = bundle.getResource(SOLR_CONFIG_XML);
- try {
- // Replace placeholders in the solr.xml config file
- m_configTemplateManager.writeConfiguration(url,
storageConfigFile);
-
- // Solr uses this system property to find its storage location.
- System.setProperty("solr.solr.home",
storageConfigFile.getParentFile().getAbsolutePath());
-
- // Update the main config
- File mainConfigDir = new File(m_workDir, "/" + CONFIG_DIR);
- mainConfigDir.mkdirs();
-
- // Find all entries in our 'conf' directory.
- final Enumeration<URL> resources =
bundle.findEntries(CONFIG_DIR, "*.*", true);
- if (resources != null) {
- while (resources.hasMoreElements()) {
- final URL resource = resources.nextElement();
- File coreConfFile = new File(mainConfigDir,
resource.getFile().replace(CONFIG_DIR + "/", ""));
- if (!coreConfFile.exists()) {
- // Only write this file if it does not yet exist
-
m_configTemplateManager.writeConfiguration(resource, coreConfFile);
+ if (!storageConfigFile.exists()) {
+ m_workDir.mkdirs();
+ Bundle bundle = m_bundleContext.getBundle();
+ URL url = bundle.getResource(SOLR_CONFIG_XML);
+ try {
+ // Replace placeholders in the solr.xml config file
+ m_configTemplateManager.writeConfiguration(url,
storageConfigFile);
+
+ // Solr uses this system property to find its storage
location.
+ System.setProperty("solr.solr.home",
storageConfigFile.getParentFile().getAbsolutePath());
+
+ // Update the main config
+ File mainConfigDir = new File(m_workDir, "/" + CONFIG_DIR);
+ mainConfigDir.mkdirs();
+
+ // Find all entries in our 'conf' directory.
+ final Enumeration<URL> resources =
bundle.findEntries(CONFIG_DIR, "*.*", true);
+ if (resources != null) {
+ while (resources.hasMoreElements()) {
+ final URL resource = resources.nextElement();
+ File coreConfFile = new File(mainConfigDir,
resource.getFile().replace(CONFIG_DIR + "/", ""));
+ if (!coreConfFile.exists()) {
+ // Only write this file if it does not yet
exist
+
m_configTemplateManager.writeConfiguration(resource, coreConfFile);
+ }
}
}
+ } catch (IOException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not replace
configuration entries in storage-conf.xml", e);
}
- } catch (IOException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not replace
configuration entries in storage-conf.xml", e);
}
-
} catch (Exception e) {
m_logService.log(LogService.LOG_ERROR, "Could not create context
component", e);
}
@@ -117,55 +110,17 @@
// Start the Solr daemon
startSolrDaemon();
+ // Register the Solr API service
+ SolrApi solrApi = registerSolrApi();
+
// Register the Solr dispatch filter
- registerRestAPI();
+ registerRestAPI(solrApi);
}
catch (Exception e) {
m_logService.log(LogService.LOG_ERROR, "Failed to start Solr
Daemon", e);
}
}
- // Invoked when a new SolrIndexProvider comes available.
- public synchronized void onIndexAdded(ServiceReference ref, Object
service) {
- if (service instanceof SolrCoreProvider) {
- SolrCoreProvider indexProvider = (SolrCoreProvider) service;
- m_logService.log(LogService.LOG_INFO, "New Solr index available: "
+ indexProvider.getCoreName());
-
- // For each tenant, prepare a Solr index (if it doesn't exist yet)
- // First create the core configuration. The name of that core will
be
- // <tenant id>/<index name>
- for (Tenant tenant : m_tenants) {
- String id = indexProvider.getCoreName();
- String core = tenant.getId() + "/" + id;
- try {
- createCoreConfiguration(core);
- }
- catch (IOException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not create
Solr core configuration for '" + core + "'", e);
- }
- }
- }
-
- }
-
- public synchronized void onIndexRemoved(ServiceReference ref, Object
service) {
- }
-
- // Invoked when a new SolrIndexProvider comes available.
- public synchronized void onTenantAdded(ServiceReference ref, Object
service) {
- if (service instanceof Tenant) {
- Tenant tenant = (Tenant) service;
- m_tenants.add(tenant);
- }
- }
-
- public synchronized void onTenantRemoved(ServiceReference ref, Object
service) {
- if (service instanceof Tenant) {
- Tenant tenant = (Tenant) service;
- m_tenants.remove(tenant);
- }
- }
-
@SuppressWarnings("unchecked")
public void updated(Dictionary dictionary) throws ConfigurationException {
if (dictionary != null) {
@@ -177,29 +132,6 @@
}
}
- @SuppressWarnings("unchecked")
- private void createCoreConfiguration(String core) throws IOException {
- File coreconfdir = new File(m_workDir, core + "/conf");
- if (coreconfdir.exists()) {
- coreconfdir.delete();
- }
- coreconfdir.mkdirs();
- Bundle bundle = m_bundleContext.getBundle();
-
- // Find all entries in our 'conf' directory.
- final Enumeration<URL> resources =
bundle.findEntries("conf_core_profile", "*.*", true);
- if (resources != null) {
- while (resources.hasMoreElements()) {
- final URL resource = resources.nextElement();
- File coreconffile = new File(coreconfdir,
resource.getFile().replace("conf_core_profile/", ""));
- if (!coreconffile.exists()) {
- // Only write this file if it does not yet exist
- m_configTemplateManager.writeConfiguration(resource,
coreconffile);
- }
- }
- }
- }
-
private void startSolrDaemon() throws Exception {
// Save the current context classloader first
final ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
@@ -209,14 +141,10 @@
final ClassLoader classLoader = this.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
- // Create the resource loader and core container
- SolrResourceLoader loader = new
NakamuraSolrResourceLoader(m_workDir.getAbsolutePath(), classLoader);
- m_coreContainer = new CoreContainer(loader);
-
// Create the core initializer
boolean abortOnConfigurationError = true;
CoreContainer.Initializer init = new CoreContainer.Initializer();
- init.initialize();
+ m_coreContainer = init.initialize();
abortOnConfigurationError = init.isAbortOnConfigurationError();
// Optionally abort if we found a sever error
@@ -243,13 +171,24 @@
}
}
+ // Register the Solr API
+ private SolrApi registerSolrApi() {
+ SolrApi solrApiService = new SolrApi(m_workDir, m_coreContainer);
+ m_dependencyManager.add(m_dependencyManager.createComponent()
+ .setImplementation(solrApiService)
+ .add(createServiceDependency(ConfigTemplateManager.class))
+ .add(createServiceDependency(LogService.class)));
+ return solrApiService;
+ }
+
// Register the REST service
- private void registerRestAPI() {
- SolrRestServiceImpl restService = new SolrRestServiceImpl(m_workDir);
+ private void registerRestAPI(SolrApi solrApi) {
+ SolrRestServiceImpl restService = new SolrRestServiceImpl(m_workDir,
solrApi);
m_dependencyManager.add(m_dependencyManager.createComponent()
.setImplementation(restService)
- .setInterface(ResourceProvider.class.getName(), null)
+ .setInterface(new String[]{SolrRestService.class.getName(),
ResourceProvider.class.getName()}, null)
.add(createServiceDependency(LogService.class))
+ .add(createServiceDependency(TenantManagementService.class))
.add(createServiceDependency(HttpContextServiceFactory.class)));
}
Modified:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
==============================================================================
---
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
(original)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrRestServiceImpl.java
Tue Jan 25 17:27:49 2011
@@ -16,25 +16,43 @@
*/
package org.amdatu.searchandindex.solr.impl;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
import java.net.URL;
import java.util.Dictionary;
import java.util.Hashtable;
import javax.servlet.Filter;
+import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.stream.XMLStreamException;
+import org.amdatu.core.tenant.Tenant;
+import org.amdatu.core.tenant.TenantException;
+import org.amdatu.core.tenant.TenantManagementService;
+import org.amdatu.searchandindex.solr.SolrRestService;
import org.amdatu.searchandindex.solr.osgi.Activator;
import org.amdatu.web.httpcontext.HttpContextServiceFactory;
import org.amdatu.web.httpcontext.ResourceProvider;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
+import org.apache.solr.client.solrj.SolrServerException;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
import org.osgi.service.log.LogService;
-
/**
* This class provides a REST interface on the Solr index service. The REST
API can be used to create, update
* and remove indices from Solr as well as performing index queries.
@@ -42,19 +60,22 @@
* @author ivol
*/
@Path("index")
-public class SolrRestServiceImpl implements ResourceProvider {
+public class SolrRestServiceImpl implements ResourceProvider, SolrRestService {
// Services injected by the Felix dependency manager
private volatile LogService m_logService;
private volatile Component m_contextComponent;
private volatile HttpContextServiceFactory m_httpContextServiceFactory;
private volatile BundleContext m_bundleContext;
private volatile DependencyManager m_dependencyManager;
+ private volatile TenantManagementService m_tenantService;
+ private volatile SolrApi m_solrApi;
// Private members
private File m_workDir;
- public SolrRestServiceImpl(File workDir) {
+ public SolrRestServiceImpl(File workDir, SolrApi solrApi) {
m_workDir = workDir;
+ m_solrApi = solrApi;
}
public void init() {
@@ -81,9 +102,9 @@
// Registers the Solr dispatch filter
private void registerSolrDispatchFilter() {
// Create and register a http servlet filter. This filter is mapped on
.*
- Dictionary<String, String> filterProperties = new Hashtable<String,
String>();
+ Dictionary<String, Object> filterProperties = new Hashtable<String,
Object>();
filterProperties.put("pattern", "/" + Activator.RESOURCE_ID +
"(|\\?.*|/.*)");
- filterProperties.put("service.ranking", "10");
+ filterProperties.put(Constants.SERVICE_RANKING, 10);
filterProperties.put("contextId", Activator.RESOURCE_ID);
SolrDispatchFilter filter = new SolrDispatchFilter("/" +
Activator.RESOURCE_ID, m_workDir.getAbsolutePath());
@@ -102,4 +123,65 @@
public String status() {
return "Index service online";
}
+
+ @PUT
+ @Path("{index}")
+ @Produces({MediaType.APPLICATION_XML})
+ public Response createIndex(@PathParam("index") final String index,
@Context final HttpServletRequest request, InputStream is) {
+ // Resolve tenant from hostname
+ String serverName = request.getServerName();
+ try {
+ for (Tenant tenant : m_tenantService.getTenants()) {
+ if (serverName.equals(tenant.getProperties().get("hostname")))
{
+ // This is the tenant for which the index should be created
+ m_solrApi.createIndex(tenant, index);
+ if (is.available() > 0) {
+ // When more then 0 bytes are available, a document is
send along with the PUT request
+ // that should be added to this index
+ m_solrApi.updateIndex(tenant, index, is);
+ }
+ }
+ }
+ }
+ catch (TenantException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (XMLStreamException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (SolrServerException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return Response.status(Response.Status.OK).build();
+ }
+
+
+ public String convertStreamToString(InputStream is)
+ throws IOException {
+ if (is != null) {
+ Writer writer = new StringWriter();
+ char[] buffer = new char[1024];
+ try {
+ Reader reader = new BufferedReader(
+ new InputStreamReader(is, "UTF-8"));
+ int n;
+ while ((n = reader.read(buffer)) != -1) {
+ writer.write(buffer, 0, n);
+ }
+ } finally {
+ is.close();
+ }
+ return writer.toString();
+ } else {
+ return "";
+ }
+ }
+
}
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrTest.java
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,174 @@
+package org.amdatu.searchandindex.solr.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.amdatu.core.tenant.TenantEntity;
+import org.amdatu.core.tenant.TenantException;
+import org.amdatu.core.tenant.TenantManagementService;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
+import org.apache.solr.common.SolrInputDocument;
+
+/**
+ * Problems found with invoking REST from a service;
+ *
+ * - If the REST performs authorization checks, how do I provide login
credentials? Should I post to some
+ * login REST service first before invoking a REST API?
+ * - How do I ensure that the REST service is online? Even providing a
required service dependency on an
+ * interface implemented by the REST service won't help, as you can never tell
when exactly the REST service
+ * is picked up by Wink. In fact, this is a general problem using the
whiteboard pattern. In this case, the
+ * REST service will NEVER be available when this service is started.
Therefore a separate thread is created.
+ *
+ */
+public class SolrTest {
+ private volatile TenantManagementService m_tenantService;
+
+ public void start() {
+ try {
+ TenantEntity tenant1 = m_tenantService.getTenantById("school_1");
+ if (tenant1 == null) {
+ tenant1 = m_tenantService.createTenant("school_1", "School 1
(localhost)");
+ tenant1.putProperty("hostname", "localhost");
+ m_tenantService.updateTenant(tenant1);
+ } else {
+ tenant1.putProperty("hostname", "localhost");
+ m_tenantService.updateTenant(tenant1);
+ }
+
+ TenantEntity tenant2 = m_tenantService.getTenantById("school_2");
+ if (tenant2 == null) {
+ tenant2 = m_tenantService.createTenant("school_2", "School 2
(127.0.0.1)");
+ tenant2.putProperty("hostname", "127.0.0.1");
+ } else {
+ tenant2.putProperty("hostname", "127.0.0.1");
+ m_tenantService.updateTenant(tenant2);
+ }
+
+ // Create new thread and start it
+ new TestThread().start();
+ } catch (TenantException e) {
+ e.printStackTrace();
+ }
+ }
+
+ class TestThread extends Thread {
+ public void run() {
+ try {
+ String baseUrl1 = "http://localhost:2237/rest/index";
+ String baseUrl2 = "http://127.0.0.1:2237/rest/index";
+
+ boolean available = false;
+ while (!available) {
+ Thread.sleep(1000);
+ available = (invokeGET(baseUrl1).statuscode ==
HttpStatus.SC_OK);
+ }
+
+ // Create indices "course" for both tenants
+ invokePUT(baseUrl1 + "/course");
+ invokePUT(baseUrl2 + "/course");
+
+ // Index a document
+ SolrInputDocument document = new SolrInputDocument();
+ document.addField( "id", "id1", 1.0f );
+ document.addField( "name", "doc1", 1.0f );
+ document.addField( "price", 10 );
+
+ streamPUT(baseUrl1 + "/course",
SolrUtil.toXMLStream(document));
+ }
+ catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private RESTResult invokeGET(String url) {
+ return invoke(url, javax.ws.rs.HttpMethod.GET);
+ }
+
+ private RESTResult invokePUT(String url) {
+ return invoke(url, javax.ws.rs.HttpMethod.PUT);
+ }
+
+ private RESTResult invoke(String url, String httpMethod) {
+ HttpClient httpClient = new HttpClient();
+ HttpMethod method = null;
+ if (httpMethod.equals(javax.ws.rs.HttpMethod.GET)) {
+ method = new GetMethod(url);
+ } else if (httpMethod.equals(javax.ws.rs.HttpMethod.PUT)) {
+ method = new PutMethod(url);
+ } else if (httpMethod.equals(javax.ws.rs.HttpMethod.DELETE)) {
+ method = new DeleteMethod(url);
+ } else if (httpMethod.equals(javax.ws.rs.HttpMethod.POST)) {
+ method = new PostMethod(url);
+ }
+ try {
+ // Execute the method, this should return a 200
+ int statusCode = httpClient.executeMethod(method);
+ RESTResult result = new RESTResult();
+ result.statuscode = statusCode;
+ result.response = new String(method.getResponseBody(), "UTF-8");
+ return result;
+ }
+ catch (HttpException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ finally {
+ // Release the connection.
+ method.releaseConnection();
+ }
+ return null;
+ }
+
+ private RESTResult streamPUT(String url, InputStream is) {
+ HttpClient httpClient = new HttpClient();
+ PutMethod method = new PutMethod(url);
+
+ try {
+ // Execute the method, this should return a 200
+ RequestEntity requestEntity = new InputStreamRequestEntity(is);
+ method.setRequestEntity(requestEntity);
+ int statusCode = httpClient.executeMethod(method);
+ RESTResult result = new RESTResult();
+ result.statuscode = statusCode;
+ result.response = new String(method.getResponseBody(), "UTF-8");
+ return result;
+ }
+ catch (HttpException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ finally {
+ // Release the connection.
+ method.releaseConnection();
+ }
+ return null;
+ }
+
+ class RESTResult {
+ public int statuscode;
+ public String response;
+ }
+}
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/impl/SolrUtil.java
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,146 @@
+package org.amdatu.searchandindex.solr.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.solr.client.solrj.util.ClientUtils;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.util.StrUtils;
+
+public class SolrUtil {
+ public static InputStream toXMLStream(SolrInputDocument document) throws
UnsupportedEncodingException {
+ String xml = ClientUtils.toXML(document);
+ InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
+ return is;
+ }
+
+ @SuppressWarnings("restriction")
+ public static SolrInputDocument fromXMLStream(InputStream is) throws
UnsupportedEncodingException, XMLStreamException {
+ // Save the current context classloader first
+ final ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
+ try {
+ // overwrite the context classloader, restore it later
+ final ClassLoader classLoader = SolrUtil.class.getClassLoader();
+ Thread.currentThread().setContextClassLoader(classLoader);
+
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ XMLStreamReader parser = factory.createXMLStreamReader(is);
+ SolrInputDocument doc = null;
+ while (true) {
+ int event = parser.next();
+ switch (event) {
+ case XMLStreamConstants.END_DOCUMENT:
+ parser.close();
+ return doc;
+
+ case XMLStreamConstants.START_ELEMENT:
+ String currTag = parser.getLocalName();
+ if ("doc".equals(currTag)) {
+ doc = readDoc(parser);
+ }
+ break;
+ }
+ }
+ } finally {
+ // Restore classloader
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+
+ }
+
+
+ @SuppressWarnings("restriction")
+ private static SolrInputDocument readDoc(XMLStreamReader parser) throws
XMLStreamException {
+ SolrInputDocument doc = new SolrInputDocument();
+
+ String attrName = "";
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ attrName = parser.getAttributeLocalName(i);
+ if ("boost".equals(attrName)) {
+ doc.setDocumentBoost(
Float.parseFloat(parser.getAttributeValue(i)) );
+ } else {
+ //log.warning("Unknown attribute doc/@" + attrName);
+ }
+ }
+
+ StringBuilder text = new StringBuilder();
+ String name = null;
+ float boost = 1.0f;
+ boolean isNull = false;
+ while (true) {
+ int event = parser.next();
+ switch (event) {
+ // Add everything to the text
+ case XMLStreamConstants.SPACE:
+ case XMLStreamConstants.CDATA:
+ case XMLStreamConstants.CHARACTERS:
+ text.append( parser.getText() );
+ break;
+
+ case XMLStreamConstants.END_ELEMENT:
+ if ("doc".equals(parser.getLocalName())) {
+ return doc;
+ }
+ else if ("field".equals(parser.getLocalName())) {
+ if (!isNull) {
+ doc.addField(name, text.toString(), boost );
+ boost = 1.0f;
+ }
+ }
+ break;
+
+ case XMLStreamConstants.START_ELEMENT:
+ text.setLength(0);
+ String localName = parser.getLocalName();
+ if (!"field".equals(localName)) {
+ //log.warning("unexpected XML tag doc/" + localName);
+ throw new
SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ "unexpected XML tag doc/" + localName);
+ }
+ boost = 1.0f;
+ String attrVal = "";
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ attrName = parser.getAttributeLocalName(i);
+ attrVal = parser.getAttributeValue(i);
+ if ("name".equals(attrName)) {
+ name = attrVal;
+ } else if ("boost".equals(attrName)) {
+ boost = Float.parseFloat(attrVal);
+ } else if ("null".equals(attrName)) {
+ isNull = StrUtils.parseBoolean(attrVal);
+ } else {
+ // log.warning("Unknown attribute doc/field/@" +
attrName);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ public static void executeInContextClassLoader(ContextExecutor executor) {
+ // Save the current context classloader first
+ final ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
+ try {
+ // overwrite the context classloader, restore it later
+ final ClassLoader classLoader = SolrUtil.class.getClassLoader();
+ Thread.currentThread().setContextClassLoader(classLoader);
+
+ // Execute stuff
+ executor.execute();
+ } finally {
+ // Restore classloader
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+
+ interface ContextExecutor {
+ void execute();
+ }
+}
Modified:
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
==============================================================================
---
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
(original)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/java/org/amdatu/searchandindex/solr/osgi/Activator.java
Tue Jan 25 17:27:49 2011
@@ -17,10 +17,12 @@
package org.amdatu.searchandindex.solr.osgi;
import org.amdatu.core.config.templates.ConfigTemplateManager;
-import org.amdatu.core.tenant.Tenant;
import org.amdatu.core.tenant.TenantManagementService;
+import org.amdatu.searchandindex.solr.SolrRestService;
import org.amdatu.searchandindex.solr.SolrService;
+import org.amdatu.searchandindex.solr.impl.NutchIndex;
import org.amdatu.searchandindex.solr.impl.SolrDaemonServiceImpl;
+import org.amdatu.searchandindex.solr.impl.SolrTest;
import org.apache.felix.dm.DependencyActivatorBase;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.BundleContext;
@@ -41,13 +43,24 @@
public void init(BundleContext context, DependencyManager manager) throws
Exception {
// Create and register the Solr service.
manager.add(createComponent()
+ .setImplementation(SolrTest.class)
+
.add(createServiceDependency().setService(SolrRestService.class).setRequired(true))
+
.add(createServiceDependency().setService(TenantManagementService.class).setRequired(true)));
+
+ // Create and register the Solr service.
+ manager.add(createComponent()
+ .setImplementation(NutchIndex.class)
+
.add(createServiceDependency().setService(SolrRestService.class).setRequired(true))
+
.add(createServiceDependency().setService(TenantManagementService.class).setRequired(true)));
+
+ // Create and register the Solr service.
+ manager.add(createComponent()
.setInterface(SolrService.class.getName(), null)
.setImplementation(SolrDaemonServiceImpl.class)
.add(createServiceDependency().setService(LogService.class).setRequired(true))
.add(createServiceDependency().setService(ConfigTemplateManager.class).setRequired(true))
.add(createServiceDependency().setService(TenantManagementService.class).setRequired(true))
- .add(createConfigurationDependency().setPid(SolrService.PID))
-
.add(createServiceDependency().setService(Tenant.class).setCallbacks("onTenantAdded",
"onTenantRemoved")));
+ .add(createConfigurationDependency().setPid(SolrService.PID)));
}
public void destroy(BundleContext context, DependencyManager manager)
throws Exception {
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/default_schema.xml
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/default_schema.xml
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+ This is the Solr schema file. This file should be named "schema.xml" and
+ should be in the conf directory under the solr home
+ (i.e. ./solr/conf/schema.xml by default)
+ or located where the classloader for the Solr webapp can find it.
+
+ This example schema is the recommended starting point for users.
+ It should be kept correct and concise, usable out-of-the-box.
+
+ For more information, on how to customize this file, please see
+ http://wiki.apache.org/solr/SchemaXml
+
+ PERFORMANCE NOTE: this schema includes many optional features and should not
+ be used for benchmarking. To improve performance one could
+ - set stored="false" for all fields possible (esp large fields) when you
+ only need to search on the field but don't need to return the original
+ value.
+ - set indexed="false" if you don't need to search on the field, but only
+ return the field as a result of searching on other indexed fields.
+ - remove all unneeded copyField statements
+ - for best index size and searching performance, set "index" to false
+ for all general text fields, use copyField to copy them to the
+ catchall "text" field, and use that for searching.
+ - For maximum indexing performance, use the StreamingUpdateSolrServer
+ java client.
+ - Remember to run the JVM in server mode, and use a higher logging level
+ that avoids logging every request
+-->
+
+<schema name="blueconic" version="1.2">
+ <!-- attribute "name" is the name of this schema and is only used for
display purposes.
+ Applications should change this to reflect the nature of the search
collection.
+ version="1.2" is Solr's version number for the schema syntax and
semantics. It should
+ not normally be changed by applications.
+ 1.0: multiValued attribute did not exist, all fields are multiValued by
nature
+ 1.1: multiValued attribute introduced, false by default
+ 1.2: omitTermFreqAndPositions attribute introduced, true by default
except for text fields.
+ -->
+
+ <types>
+ <!-- field type definitions. The "name" attribute is
+ just a label to be used by field definitions. The "class"
+ attribute and any other attributes determine the real
+ behavior of the fieldType.
+ Class names starting with "solr" refer to java classes in the
+ org.apache.solr.analysis package.
+ -->
+
+ <!-- The StrField type is not analyzed, but indexed/stored verbatim.
+ - StrField and TextField support an optional compressThreshold which
+ limits compression (if enabled in the derived fields) to values which
+ exceed a certain size (in characters).
+ -->
+ <fieldType name="string" class="solr.StrField" sortMissingLast="true"
omitNorms="true"/>
+
+ <!-- boolean type: "true" or "false" -->
+ <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"
omitNorms="true"/>
+ <!--Binary data type. The data should be sent/retrieved in as Base64
encoded Strings -->
+ <fieldtype name="binary" class="solr.BinaryField"/>
+
+ <!-- The optional sortMissingLast and sortMissingFirst attributes are
+ currently supported on types that are sorted internally as strings.
+ This includes
"string","boolean","sint","slong","sfloat","sdouble","pdate"
+ - If sortMissingLast="true", then a sort on this field will cause
documents
+ without the field to come after documents with the field,
+ regardless of the requested sort order (asc or desc).
+ - If sortMissingFirst="true", then a sort on this field will cause
documents
+ without the field to come before documents with the field,
+ regardless of the requested sort order.
+ - If sortMissingLast="false" and sortMissingFirst="false" (the default),
+ then default lucene sorting will be used which places docs without the
+ field first in an ascending sort and last in a descending sort.
+ -->
+
+ <!--
+ Default numeric field types. For faster range queries, consider the
tint/tfloat/tlong/tdouble types.
+ -->
+ <fieldType name="int" class="solr.TrieIntField" precisionStep="0"
omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="float" class="solr.TrieFloatField" precisionStep="0"
omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="long" class="solr.TrieLongField" precisionStep="0"
omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="double" class="solr.TrieDoubleField" precisionStep="0"
omitNorms="true" positionIncrementGap="0"/>
+
+ <!--
+ Numeric field types that index each value at various levels of precision
+ to accelerate range queries when the number of values between the range
+ endpoints is large. See the javadoc for NumericRangeQuery for internal
+ implementation details.
+
+ Smaller precisionStep values (specified in bits) will lead to more tokens
+ indexed per value, slightly larger index size, and faster range queries.
+ A precisionStep of 0 disables indexing at different precision levels.
+ -->
+ <fieldType name="tint" class="solr.TrieIntField" precisionStep="8"
omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8"
omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tlong" class="solr.TrieLongField" precisionStep="8"
omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8"
omitNorms="true" positionIncrementGap="0"/>
+
+ <!-- The format for this date field is of the form 1995-12-31T23:59:59Z,
and
+ is a more restricted form of the canonical representation of dateTime
+ http://www.w3.org/TR/xmlschema-2/#dateTime
+ The trailing "Z" designates UTC time and is mandatory.
+ Optional fractional seconds are allowed: 1995-12-31T23:59:59.999Z
+ All other components are mandatory.
+
+ Expressions can also be used to denote calculations that should be
+ performed relative to "NOW" to determine the value, ie...
+
+ NOW/HOUR
+ ... Round to the start of the current hour
+ NOW-1DAY
+ ... Exactly 1 day prior to now
+ NOW/DAY+6MONTHS+3DAYS
+ ... 6 months and 3 days in the future from the start of
+ the current day
+
+ Consult the DateField javadocs for more information.
+
+ Note: For faster range queries, consider the tdate type
+ -->
+ <fieldType name="date" class="solr.TrieDateField" omitNorms="true"
precisionStep="0" positionIncrementGap="0"/>
+
+ <!-- A Trie based date field for faster date range queries and date
faceting. -->
+ <fieldType name="tdate" class="solr.TrieDateField" omitNorms="true"
precisionStep="6" positionIncrementGap="0"/>
+
+
+ <!--
+ Note:
+ These should only be used for compatibility with existing indexes
(created with older Solr versions)
+ or if "sortMissingFirst" or "sortMissingLast" functionality is needed.
Use Trie based fields instead.
+
+ Plain numeric field types that store and index the text
+ value verbatim (and hence don't support range queries, since the
+ lexicographic ordering isn't equal to the numeric ordering)
+ -->
+ <fieldType name="pint" class="solr.IntField" omitNorms="true"/>
+ <fieldType name="plong" class="solr.LongField" omitNorms="true"/>
+ <fieldType name="pfloat" class="solr.FloatField" omitNorms="true"/>
+ <fieldType name="pdouble" class="solr.DoubleField" omitNorms="true"/>
+ <fieldType name="pdate" class="solr.DateField" sortMissingLast="true"
omitNorms="true"/>
+
+
+ <!--
+ Note:
+ These should only be used for compatibility with existing indexes
(created with older Solr versions)
+ or if "sortMissingFirst" or "sortMissingLast" functionality is needed.
Use Trie based fields instead.
+
+ Numeric field types that manipulate the value into
+ a string value that isn't human-readable in its internal form,
+ but with a lexicographic ordering the same as the numeric ordering,
+ so that range queries work correctly.
+ -->
+ <fieldType name="sint" class="solr.SortableIntField"
sortMissingLast="true" omitNorms="true"/>
+ <fieldType name="slong" class="solr.SortableLongField"
sortMissingLast="true" omitNorms="true"/>
+ <fieldType name="sfloat" class="solr.SortableFloatField"
sortMissingLast="true" omitNorms="true"/>
+ <fieldType name="sdouble" class="solr.SortableDoubleField"
sortMissingLast="true" omitNorms="true"/>
+
+
+ <!-- The "RandomSortField" is not used to store or search any
+ data. You can declare fields of this type it in your schema
+ to generate pseudo-random orderings of your docs for sorting
+ purposes. The ordering is generated based on the field name
+ and the version of the index, As long as the index version
+ remains unchanged, and the same field name is reused,
+ the ordering of the docs will be consistent.
+ If you want different psuedo-random orderings of documents,
+ for the same version of the index, use a dynamicField and
+ change the name
+ -->
+ <fieldType name="random" class="solr.RandomSortField" indexed="true" />
+
+ <!-- solr.TextField allows the specification of custom text analyzers
+ specified as a tokenizer and a list of token filters. Different
+ analyzers may be specified for indexing and querying.
+
+ The optional positionIncrementGap puts space between multiple fields
of
+ this type on the same document, with the purpose of preventing false
phrase
+ matching across fields.
+
+ For more info on customizing your analyzer chain, please see
+ http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters
+ -->
+
+ <!-- One can also specify an existing Analyzer class that has a
+ default constructor via the class attribute on the analyzer element
+ <fieldType name="text_greek" class="solr.TextField">
+ <analyzer class="org.apache.lucene.analysis.el.GreekAnalyzer"/>
+ </fieldType>
+ -->
+
+ <!-- A text field that only splits on whitespace for exact matching of
words -->
+ <fieldType name="text_ws" class="solr.TextField"
positionIncrementGap="100">
+ </fieldType>
+
+ <!-- A text field that uses WordDelimiterFilter to enable splitting and
matching of
+ words on case-change, alpha numeric boundaries, and non-alphanumeric
chars,
+ so that a query of "wifi" or "wi fi" could match a document containing
"Wi-Fi".
+ Synonyms and stopwords are customized by external files, and stemming
is enabled.
+ -->
+ <fieldType name="text" class="solr.TextField" positionIncrementGap="100">
+ </fieldType>
+
+ <!-- A general unstemmed text field - good if one does not know the
language of the field -->
+ <fieldType name="textgen" class="solr.TextField"
positionIncrementGap="100">
+ </fieldType>
+
+ <!-- A general unstemmed text field that indexes tokens normally and also
+ reversed (via ReversedWildcardFilterFactory), to enable more
efficient
+ leading wildcard queries. -->
+ <fieldType name="text_rev" class="solr.TextField"
positionIncrementGap="100">
+ </fieldType>
+
+ <!-- since fields of this type are by default not stored or indexed,
+ any data added to them will be ignored outright. -->
+ <fieldtype name="ignored" stored="false" indexed="false"
multiValued="true" class="solr.StrField" />
+ </types>
+
+
+ <fields>
+ <!-- Valid attributes for fields:
+ name: mandatory - the name for the field
+ type: mandatory - the name of a previously defined type from the
+ <types> section
+ indexed: true if this field should be indexed (searchable or sortable)
+ stored: true if this field should be retrievable
+ compressed: [false] if this field should be stored using gzip compression
+ (this will only apply if the field type is compressable; among
+ the standard field types, only TextField and StrField are)
+ multiValued: true if this field may contain multiple values per document
+ omitNorms: (expert) set to true to omit the norms associated with
+ this field (this disables length normalization and index-time
+ boosting for the field, and saves some memory). Only full-text
+ fields or fields that need an index-time boost need norms.
+ termVectors: [false] set to true to store the term vector for a
+ given field.
+ When using MoreLikeThis, fields used for similarity should be
+ stored for best performance.
+ termPositions: Store position information with the term vector.
+ This will increase storage costs.
+ termOffsets: Store offset information with the term vector. This
+ will increase storage costs.
+ default: a value that should be used if no value is specified
+ when adding a document.
+ -->
+
+ <field name="id" type="string" indexed="true" stored="true" required="true"
/>
+
+ <!-- catchall field, containing all other searchable text fields
(implemented
+ via copyField further on in this schema -->
+ <field name="text" type="text" indexed="true" stored="false"
multiValued="true"/>
+
+ <field name="timestamp" type="date" indexed="true" stored="false"
default="NOW" multiValued="false"/>
+
+ <dynamicField name="*_i" type="sint" indexed="true" stored="false"
omitNorms="true" multiValued="true"/>
+ <dynamicField name="*_s" type="string" indexed="true" stored="false"
multiValued="true"/>
+ <dynamicField name="*_l" type="long" indexed="true" stored="false"/>
+ <dynamicField name="*_t" type="text" indexed="true" stored="false"/>
+ <dynamicField name="*_b" type="boolean" indexed="true" stored="false"/>
+ <dynamicField name="*_f" type="float" indexed="true" stored="false"/>
+ <dynamicField name="*_d" type="double" indexed="true" stored="false"/>
+ <dynamicField name="*_dt" type="date" indexed="true" stored="false"/>
+
+ <!-- some trie-coded dynamic fields for faster range queries -->
+ <dynamicField name="*_ti" type="tint" indexed="true" stored="false"/>
+ <dynamicField name="*_tl" type="tlong" indexed="true" stored="false"/>
+ <dynamicField name="*_tf" type="tfloat" indexed="true" stored="false"/>
+ <dynamicField name="*_td" type="tdouble" indexed="true" stored="false"/>
+ <dynamicField name="*_tdt" type="tdate" indexed="true" stored="false"/>
+
+ <dynamicField name="*_pi" type="pint" indexed="true" stored="false"/>
+
+ <dynamicField name="ignored_*" type="ignored" multiValued="true"/>
+ <dynamicField name="attr_*" type="textgen" indexed="true" stored="false"
multiValued="true"/>
+
+ <dynamicField name="random_*" type="random" />
+
+ <!-- uncomment the following to ignore any fields that don't already match
an existing
+ field name or dynamic field, rather than reporting them as an error.
+ alternately, change the type="ignored" to some other type e.g. "text"
if you want
+ unknown fields indexed and/or stored by default -->
+ <!--dynamicField name="*" type="ignored" multiValued="true" /-->
+
+ </fields>
+
+ <!-- Field to use to determine and enforce document uniqueness.
+ Unless this field is marked with required="false", it will be a required
field
+ -->
+ <uniqueKey>id</uniqueKey>
+
+ <!-- field for the QueryParser to use when an explicit fieldname is absent -->
+ <defaultSearchField>text</defaultSearchField>
+
+ <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
+ <solrQueryParser defaultOperator="OR"/>
+</schema>
Added:
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/default_solrconfig.xml
==============================================================================
--- (empty file)
+++
sandbox/ivol/amdatu-searchandindex/solr/src/main/resources/default_solrconfig.xml
Tue Jan 25 17:27:49 2011
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+
+ http://wiki.apache.org/solr/SolrConfigXml
+
+-->
+
+<config>
+ <indexDefaults>
+ <!-- Sets the amount of RAM that may be used by Lucene indexing
+ for buffering added documents and deletions before they are
+ flushed to the Directory. -->
+ <ramBufferSizeMB>32</ramBufferSizeMB>
+ <lockType>simple</lockType>
+ <!--
+ Expert:
+ Controls how often Lucene loads terms into memory -->
+ <!--<termIndexInterval>256</termIndexInterval>-->
+ </indexDefaults>
+
+ <jmx />
+
+ <query>
+ <maxBooleanClauses>102400</maxBooleanClauses>
+ </query>
+
+ <updateHandler class="solr.DirectUpdateHandler2" />
+
+ <requestDispatcher handleSelect="true" >
+ <requestParsers enableRemoteStreaming="false"
multipartUploadLimitInKB="2048" />
+ </requestDispatcher>
+
+ <requestHandler name="standard" class="solr.StandardRequestHandler"
default="true">
+ <arr name="last-components">
+ </arr>
+ </requestHandler>
+
+ <requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
+ <requestHandler name="/admin/"
class="org.apache.solr.handler.admin.AdminHandlers" />
+
+ <!-- config for the admin interface -->
+ <admin>
+ <defaultQuery>solr</defaultQuery>
+ </admin>
+
+</config>
+