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) {