Index: web/conf/config.ini
===================================================================
--- web/conf/config.ini (revision 3015)
+++ web/conf/config.ini (working copy)
@@ -81,6 +81,16 @@
local = /usr/local/vufind/solr
default_core = biblio
+; This section allows sharding to be used to pull in content from additional Solr
+; servers. All servers used in sharding must contain the same index fields needed
+; to satisfy queries sent to them! Leave this commented out to disable sharding.
+; To use sharding, simply fill in lines using the format:
+; [display name of shard] = [URL of shard (without http://)]
+;[IndexShards]
+;Library Catalog = localhost:8080/solr/biblio
+;Weblog = localhost:8080/solr/weblog
+;Website = localhost:8080/solr/website
+
; This section requires no changes for most installations; if your SMTP server
; requires authentication, you can fill in a username and password below.
[Mail]
Index: web/conf/facets.ini
===================================================================
--- web/conf/facets.ini (revision 3015)
+++ web/conf/facets.ini (working copy)
@@ -22,6 +22,14 @@
[ResultsTop]
topic_facet = "Suggested Topics"
+; Facets must be stripped if you have a facet in your main index which is missing
+; from any index includable by shards. This section can be ignored if you are
+; not using sharding or if all of your shards have identical schemas.
+;
+; Put in the facets to strip here in the following format:
+; shard name = fieldname,another fieldname,...
+[StripFacets]
+
; This section is reserved for special boolean facets. These are displayed
; as checkboxes. If the box is checked, the filter on the left side of the
; equal sign is applied. If the box is not checked, the filter is not applied.
Index: web/index.php
===================================================================
--- web/index.php (revision 3015)
+++ web/index.php (working copy)
@@ -155,6 +155,9 @@
processFollowup();
}
+// Process Solr shard settings
+processShards();
+
// Call Action
if (is_readable("services/$module/$action.php")) {
require_once "services/$module/$action.php";
@@ -194,6 +197,36 @@
}
}
+function processShards()
+{
+ global $configArray;
+ global $interface;
+
+ // If shards are not configured, give up now:
+ if (!isset($configArray['IndexShards']) || empty($configArray['IndexShards'])) {
+ return;
+ }
+
+ // If a shard selection list is found as an incoming parameter, we should save
+ // it in the session for future reference:
+ if (array_key_exists('shard', $_REQUEST)) {
+ $_SESSION['shards'] = $_REQUEST['shard'];
+ // If no selection list was passed in, select all shards by default:
+ } else if (!array_key_exists('shards', $_SESSION)) {
+ $_SESSION['shards'] = array_keys($configArray['IndexShards']);
+ }
+
+ // If we are configured to use shards, send a list of shards to the interface,
+ // with keys being shard names and values being a boolean value indicating
+ // whether or not the shard is currently selected.
+ $shards = array();
+ foreach ($configArray['IndexShards'] as $shardName => $shardAddress) {
+ $shards[$shardName] = in_array($shardName, $_SESSION['shards']);
+ }
+
+ $interface->assign('shards', $shards);
+}
+
// Process any errors that are thrown
function handlePEARError($error, $method = null)
{
Index: web/interface/themes/default/Search/searchbox.tpl
===================================================================
--- web/interface/themes/default/Search/searchbox.tpl (revision 3015)
+++ web/interface/themes/default/Search/searchbox.tpl (working copy)
@@ -24,6 +24,11 @@
{/if}
{/foreach}
{/if}
+ {if $shards}
+ {foreach from=$shards key=shard item=isSelected}
+ {$shard|escape}
+ {/foreach}
+ {/if}
{if $filterList || $hasCheckboxFilters}
{translate text="basic_search_keep_filters"}
Index: web/sys/SearchObject/Solr.php
===================================================================
--- web/sys/SearchObject/Solr.php (revision 3015)
+++ web/sys/SearchObject/Solr.php (working copy)
@@ -909,6 +909,11 @@
// this null in order to achieve the desired effect with Solr:
$finalSort = ($this->sort == 'relevance') ? null : $this->sort;
+ // Load additional indices for distributed search
+ if (isset($_SESSION['shards'])) {
+ $this->fields = '*,score';
+ }
+
// The first record to retrieve:
// (page - 1) * limit = start
$recordStart = ($this->page - 1) * $this->limit;
Index: web/sys/Solr.php
===================================================================
--- web/sys/Solr.php (revision 3015)
+++ web/sys/Solr.php (working copy)
@@ -83,7 +83,9 @@
* case-insensitive (false), or must they be ALL UPPERCASE (true)?
*/
private $caseSensitiveBooleans = true;
-
+
+ private $solrShards = array();
+
/**
* Constructor
*
@@ -101,7 +103,7 @@
$index = isset($configArray['Index']['default_core']) ?
$configArray['Index']['default_core'] : "biblio";
}
-
+
$this->host = $host . '/' . $index;
// Test to see solr is online
@@ -128,6 +130,17 @@
$this->caseSensitiveBooleans =
$searchSettings['General']['case_sensitive_bools'];
}
+
+ // Deal with session-based shard settings:
+ if (isset($_SESSION['shards'])) {
+ $shards = array();
+ foreach($_SESSION['shards'] as $current) {
+ if (isset($configArray['IndexShards'][$current])) {
+ $shards[$current] = $configArray['IndexShards'][$current];
+ }
+ }
+ $this->setShards($shards);
+ }
}
/**
@@ -915,6 +928,59 @@
}
/**
+ * Set the shards for distributed search
+ *
+ * @param array $shards Name => URL array of shards
+ */
+ public function setShards($shards) {
+ $this->solrShards = $shards;
+ }
+
+ /**
+ * Strip facet settings that are illegal due to shard settings.
+ *
+ * @param array $value Current facet.field setting
+ * @return array Filtered facet.field setting
+ */
+ private function stripUnwantedFacets($value)
+ {
+ // Load the configuration of facets to strip and build a list of the ones
+ // that currently apply:
+ $facetConfig = getExtraConfigArray('facets');
+ $badFacets = array();
+ if (!empty($this->solrShards) && is_array($this->solrShards) &&
+ isset($facetConfig['StripFacets']) &&
+ is_array($facetConfig['StripFacets'])) {
+ $shardNames = array_keys($this->solrShards);
+ foreach ($facetConfig['StripFacets'] as $indexName => $facets) {
+ if (in_array($indexName, $shardNames) === true) {
+ $badFacets = array_merge($badFacets, explode(",", $facets));
+ }
+ }
+ }
+
+ // No bad facets means no filtering necessary:
+ if (empty($badFacets)) {
+ return $value;
+ }
+
+ // Ensure that $value is an array:
+ if (!is_array($value)) {
+ $value = array($value);
+ }
+
+ // Rebuild the $value array, excluding all unwanted facets:
+ $newValue = array();
+ foreach($value as $current) {
+ if (!in_array($current, $badFacets)) {
+ $newValue[] = $current;
+ }
+ }
+
+ return $newValue;
+ }
+
+ /**
* Submit REST Request to read data
*
* @param string $method HTTP Method to use: GET, POST,
@@ -939,6 +1005,15 @@
if ($params) {
foreach ($params as $function => $value) {
if ($function != '') {
+ // Strip custom FacetFields when sharding makes it necessary:
+ if ($function === 'facet.field') {
+ $value = $this->stripUnwantedFacets($value);
+
+ // If we stripped all values, skip the parameter:
+ if (empty($value)) {
+ continue;
+ }
+ }
if(is_array($value)) {
foreach ($value as $additional) {
$additional = urlencode($additional);
@@ -951,6 +1026,10 @@
}
}
}
+ if (!empty($this->solrShards) && is_array($this->solrShards)) {
+ // strip custom FacetField since its not in other indices
+ $query[] = 'shards=' . urlencode(implode(',', $this->solrShards));
+ }
$queryString = implode('&', $query);
if ($this->debug) {