diff --git a/code/solr/Solr.php b/code/solr/Solr.php index 582032a..42ffff4 100644 --- a/code/solr/Solr.php +++ b/code/solr/Solr.php @@ -10,6 +10,12 @@ class Solr { * port (default: 8983) - The port Solr is listening on * path (default: /solr) - The suburl the solr service is available on * + * Optional fields: + * extraspath (default: /fulltextsearch/conf/extras/) - Absolute path to + * the folder containing templates which are used for generating the schema and field definitions. + * templates (default: /fulltextsearch/conf/templates/) - Absolute path to + * the configuration default files, e.g. solrconfig.xml. + * * indexstore => an array with * * mode - 'file' or 'webdav' @@ -29,7 +35,9 @@ class Solr { self::$solr_options = array_merge(array( 'host' => 'localhost', 'port' => 8983, - 'path' => '/solr' + 'path' => '/solr', + 'extraspath' => Director::baseFolder().'/fulltextsearch/conf/extras/', + 'templatespath' => Director::baseFolder().'/fulltextsearch/conf/templates/', ), self::$solr_options, $options); } @@ -92,14 +100,17 @@ class Solr_Configure extends BuildTask { $remote = isset($index['remotepath']) ? $index['remotepath'] : $local; foreach (Solr::get_indexes() as $index => $instance) { - $confdir = "$local/$index/conf"; - if (!is_dir($confdir)) mkdir($confdir, 0770, true); + $sourceDir = $instance->getExtrasPath(); + $targetDir = "$local/$index/conf"; + if (!is_dir($targetDir)) mkdir($targetDir, 0770, true); - file_put_contents("$confdir/schema.xml", $instance->generateSchema()); + file_put_contents("$targetDir/schema.xml", $instance->generateSchema()); - foreach (glob(Director::baseFolder().'/fulltextsearch/conf/extras/*') as $file) { - if (is_file($file)) copy($file, $confdir.'/'.basename($file)); + echo sprintf("Copying %s to %s...", $sourceDir, $targetDir); + foreach (glob($sourceDir . '/*') as $file) { + if (is_file($file)) copy($file, $targetDir.'/'.basename($file)); } + echo "done\n"; } break; @@ -118,14 +129,17 @@ class Solr_Configure extends BuildTask { $indexdir = "$url/$index"; if (!WebDAV::exists($indexdir)) WebDAV::mkdir($indexdir); - $confdir = "$url/$index/conf"; - if (!WebDAV::exists($confdir)) WebDAV::mkdir($confdir); + $sourceDir = $instance->getExtrasPath(); + $targetDir = "$url/$index/conf"; + if (!WebDAV::exists($targetDir)) WebDAV::mkdir($targetDir); - WebDAV::upload_from_string($instance->generateSchema(), "$confdir/schema.xml"); + WebDAV::upload_from_string($instance->generateSchema(), "$targetDir/schema.xml"); - foreach (glob(Director::baseFolder().'/fulltextsearch/conf/extras/*') as $file) { - if (is_file($file)) WebDAV::upload_from_file($file, $confdir.'/'.basename($file)); + echo sprintf("Copying %s to %s (via WebDAV)...", $sourceDir, $targetDir); + foreach (glob($sourceDir . '/*') as $file) { + if (is_file($file)) WebDAV::upload_from_file($file, $targetDir.'/'.basename($file)); } + echo "done\n"; } break; diff --git a/code/solr/SolrIndex.php b/code/solr/SolrIndex.php index d56c83c..8a2f3e1 100644 --- a/code/solr/SolrIndex.php +++ b/code/solr/SolrIndex.php @@ -24,8 +24,27 @@ abstract class SolrIndex extends SearchIndex { static $sortTypeMap = array(); + protected $extrasPath = null; + + protected $templatesPath = null; + /** + * @return String Absolute path to the folder containing + * templates which are used for generating the schema and field definitions. + */ + function getTemplatesPath() { + return $this->templatesPath ? $this->templatesPath : Solr::$solr_options['templatespath']; + } + + /** + * @return String Absolute path to the configuration default files, + * e.g. solrconfig.xml. + */ + function getExtrasPath() { + return $this->extrasPath ? $this->extrasPath : Solr::$solr_options['extraspath']; + } + function generateSchema() { - return $this->renderWith(Director::baseFolder() . '/fulltextsearch/conf/templates/schema.ss'); + return $this->renderWith($this->getTemplatesPath() . '/schema.ss'); } function getIndexName() { @@ -33,7 +52,7 @@ abstract class SolrIndex extends SearchIndex { } function getTypes() { - return $this->renderWith(Director::baseFolder() . '/fulltextsearch/conf/templates/types.ss'); + return $this->renderWith($this->getTemplatesPath() . '/types.ss'); } function getFieldDefinitions() { diff --git a/docs/Solr.md b/docs/Solr.md index 6ece250..d3d5fc5 100644 --- a/docs/Solr.md +++ b/docs/Solr.md @@ -32,10 +32,16 @@ by the user the Solr search server is started with (see below). 'host' => 'localhost', 'indexstore' => array( 'mode' => 'file', - 'path' => BASE_PATH . '/fulltextsearch/thirdparty/fulltextsearch/server/solr' + 'path' => BASE_PATH . '/.solr' ) )); +Note: We recommend to put the `indexstore.path` directory outside of the webroot. +If you place it inside of the webroot (as shown in the example), +please ensure its contents are not accessible through the webserver. +This can be achieved by server configuration, or (in most configurations) +also by marking the folder as hidden via a "dot" prefix. + Create an index // File: mysite/code/MyIndex.php: @@ -56,6 +62,16 @@ Initialize the configuration (via CLI) sake dev/tasks/Solr_configure +Based on the sample configuration above, this command will do the following: + +- Create a /.solr/MyIndex` folder +- Copy configuration files from `fulltextsearch/conf/extras/` to `/.solr/MyIndex/conf` +- Generate a `schema.xml`, and place it it in `/.solr/MyIndex/conf` + +If you call the `Solr_configure` task with an existing index folder, +it will overwrite all files from their default locations, +regenerate the `schema.xml`, and ask Solr to reload the configuration. + ## Usage After configuring Solr, you have the option to add your existing @@ -63,7 +79,14 @@ content to its indices. Run the following command: sake dev/tasks/Solr_reindex -This will rebuild all indices. You can narrow down the operation with the following options: +This will delete and rebuild all indices. Depending on your data, +this can take anywhere from minutes to hours. +Keep in mind that the normal mode of updating indices is +based on ORM manipulations of the underlying data. +For example, calling `$myPage->write()` will automatically +update the index entry for this record (and all its variants). + +You can narrow down the operation with the following options: - `index`: PHP class name of an index - `class`: PHP model class to reindex @@ -72,9 +95,31 @@ This will rebuild all indices. You can narrow down the operation with the follow - `verbose`: Debug information Note: The Solr indexes will be stored as binary files inside your SilverStripe project. -You can also copy the `thirdparty/`solr directory somewhere else, -just set the path value in `mysite/_config.php` to point to the new location. -And of course run `java -jar start.jar` from the new directory. +You can also copy the `thirdparty/` solr directory somewhere else, +just set the `path` value in `mysite/_config.php` to point to the new location. + +### File-based configuration (solrconfig.xml etc) + +Many aspects of Solr are configured outside of the `schema.xml` file +which SilverStripe generates based on the index PHP file. +For example, stopwords are placed in their own `stopwords.txt` file, +and spell checks are configured in `solrconfig.xml`. + +By default, these files are copied from the `fulltextsearch/conf/extras/` +directory over to the new index location. In order to use your own files, +copy these files into a location of your choosing (for example `mysite/data/solr/`), +and tell Solr to use this folder with the `extraspath` configuration setting. + + // mysite/_config.php + Solr::configure_server(array( + // ... + 'extraspath' => Director::baseFolder() . '/mysite/data/solr/', + )); + +Please run the `Solr_configure` task for the changes to take effect. + +Note: You can also define those on an index-by-index basis by +implementing `SolrIndex->getExtrasPath()`. ### Custom Types