updated search_api and search_api_solr

This commit is contained in:
Bachir Soussi Chiadmi
2016-03-01 16:23:45 +01:00
parent deb2bff572
commit ba1ec7113e
67 changed files with 5209 additions and 686 deletions

View File

@@ -1,4 +1,56 @@
Search API Solr search 1.6 (09/08/2014):
Search API Solr Search 1.x, dev (xxxx-xx-xx):
---------------------------------------------
- #2645366 by tedfordgif, drunken monkey: Fixed browser incorrectly filling the
HTTP Auth form fields.
- #2611716 by aditya_anurag, drunken monkey: Improved the method documentation
comments.
- #2599658 by Loparev, drunken monkey: Added the possibility to highlight
non-fulltext fields.
- #2598288 by ethan.han777, JeroenT, drunken monkey: Fixed potential notices in
the spellchecker code.
- #2564927 by thePanz: Added support for random sorting in grouped searches.
- #2527528 by maximpodorov, drunken monkey: Fixed searching of string fields
with leading/trailing spaces.
- #2513314 by fortis, drunken monkey: Fixed error for empty filters.
- #2551763 by drunken monkey: Fixed mention of INSTALL.txt in an error message.
Search API Solr Search 1.9 (2015-08-30):
----------------------------------------
- #2503829 by das-peter: Added support for grouping on "magic" fields.
- #2503617 by tobiasb: Fixed undefined "status_message" property in HTTP
response object.
- #2313591 by thePanz, nadavoid: Added support for random sorting.
- #2004596 by drunken monkey: Fixed workarounds for MLT problems.
- #2486533 by drunken monkey: Fixed the default operator in the Solr 5 configs.
- #2466897 by drunken monkey: Fixed Solr version options in server settings.
- #1918904 by arnested, ramlev, drunken monkey: Added an alter hook for
autocomplete suggestions.
- #2532812 by drunken monkey: Improved performance for filter-only queries.
- #2463523 by bmunslow: Fixed field boosts in multi-index searches.
Search API Solr Search 1.8 (2015-06-15):
----------------------------------------
- #2502511 by drunken monkey: Fixed index removal on Solr 5.
- #2441117 by drunken monkey: Fixed unnecessary reindexing after changing
fields' boosts.
Search API Solr Search 1.7 (2015-06-08):
----------------------------------------
- #2466489 by drunken monkey: Changed installation instructions to point to the
handbook.
- #2486533 by drunken monkey: Fixed default operator in Solr 5.
- #2456159 by drunken monkey: Updated config files to their latest version from
the common configs.
- #2442077 by drunken monkey, basvredeling: Added support for Solr 5.
- #2451037 by drunken monkey: Fixed timeout errors during indexing.
- #2054551 by paolomainardi, drunken monkey, lex0r: Added possibility to
retrieve Solr field values in multi-index searches.
- #1908990 by drunken monkey: Fixed various issues with excerpts.
- #2368399 by das-peter, drunken monkey: Added Support for location filtering
with a bounding box.
- #2333133 by drunken monkey: Fixed behavior of filters on fulltext fields.
Search API Solr Search 1.6 (2014-09-08):
----------------------------------------
- #2050961 by das-peter, drunken monkey: Added proximity/distance information
to search results.
@@ -10,7 +62,7 @@ Search API Solr search 1.6 (09/08/2014):
- #2270767 by RaF: Fixed search_api_solr_views_data_alter() not always
returning all virtual fields.
Search API Solr search 1.5 (05/23/2014):
Search API Solr Search 1.5 (2014-05-23):
----------------------------------------
- #2216895 by das-peter: Added support for empty/non-empty conditions on
location field types.
@@ -30,7 +82,7 @@ Search API Solr search 1.5 (05/23/2014):
only” queries.
- #2147573 by drunken monkey: Improved error handling.
Search API Solr search 1.4 (12/25/2013):
Search API Solr Search 1.4 (2013-12-25):
----------------------------------------
- #2157839 by drunken monkey, Nick_vh: Updated config files to the newest
version.
@@ -48,7 +100,7 @@ Search API Solr search 1.4 (12/25/2013):
- #2064377 by Nick_vh: Made configuration files compatible with Solr Cloud.
- #2107417 by Nick_vh: Fixed config files for Solr 4.5.
Search API Solr search 1.3 (10/23/2013):
Search API Solr Search 1.3 (2013-10-23):
----------------------------------------
- #2099683 by drunken monkey: Added support for 'virtual fields' in Views.
- #1997702 by ianthomas_uk, drunken monkey: Added "AUTO" mode for HTTP method.
@@ -58,7 +110,7 @@ Search API Solr search 1.3 (10/23/2013):
- #1882190 by corvus_ch, arnested, drunken monkey: Added optional index ID
prefixes.
Search API Solr search 1.2 (09/01/2013):
Search API Solr Search 1.2 (2013-09-01):
----------------------------------------
- #1246730 by febbraro, maciej.zgadzaj, drunken monkey: Added a way to alter
the Solr document when indexing.
@@ -69,7 +121,7 @@ Search API Solr search 1.2 (09/01/2013):
- #2045355 by drunken monkey, arpieb: Fixed result mapping of item IDs.
- #2050157 by izus: Fixed typo in stopwords.txt.
Search API Solr search 1.1 (07/21/2013):
Search API Solr Search 1.1 (2013-07-21):
----------------------------------------
- #1957730 by drunken monkey: Fixed filter query strings for negated filters.
- #2010818 by kenorb, drunken monkey: Added new Files tab showing all used solr
@@ -84,7 +136,7 @@ Search API Solr search 1.1 (07/21/2013):
multi-valued fields.
- #2008034 by bdecarne: Fixed highlighting in multi-index searches.
Search API Solr search 1.0 (06/09/2013):
Search API Solr Search 1.0 (2013-06-09):
----------------------------------------
- #1896080 by drunken monkey: Included additional required config files in the
module.
@@ -98,7 +150,7 @@ Search API Solr search 1.0 (06/09/2013):
support.
- #1549244 by cferthorney, drunken monkey: Added SSL Support for Solr servers.
Search API Solr search 1.0, RC 5 (05/17/2013):
Search API Solr Search 1.0, RC 5 (2013-05-17):
----------------------------------------------
- #1190462 by drunken monkey: Documented that enabling HTML filter makes sense.
- #1986284 by drunken monkey: Updated common configs to the latest version.
@@ -112,7 +164,7 @@ Search API Solr search 1.0, RC 5 (05/17/2013):
- #1978600 by chaby: Fixed hook_requirements() for install phase.
- #1976930 by drunken monkey: Fixed duplicate method in SearchApiSolrField.
Search API Solr search 1.0, RC 4 (04/22/2013):
Search API Solr Search 1.0, RC 4 (2013-04-22):
----------------------------------------------
- #1744250 by mollux, drunken monkey, das-peter: Added support for
location-based searches.
@@ -122,7 +174,7 @@ Search API Solr search 1.0, RC 4 (04/22/2013):
- #1900644 by Deciphered: Fixed facet handling for multi-index searches.
- #1897386 by drunken monkey, NIck_vh: Update the common schema.
Search API Solr search 1.0, RC 3 (01/06/2013):
Search API Solr Search 1.0, RC 3 (2013-01-06):
----------------------------------------------
- #1828260 by drunken monkey: Fixed filtering by index in multi-index searches.
- #1509380 by drunken monkey: Adopt common config files.
@@ -141,7 +193,7 @@ Search API Solr search 1.0, RC 3 (01/06/2013):
- #1299940 by drunken monkey: Fixed handling of empty response.
- #1507818 by larowlan: Fixed field boosts for standard request handler.
Search API Solr search 1.0, RC 2 (05/23/2012):
Search API Solr Search 1.0, RC 2 (2012-05-23):
----------------------------------------------
- Fixed escaping of error messages.
- #1480170 by kotnik: Fixed return value of hook_requirements().
@@ -151,14 +203,14 @@ Search API Solr search 1.0, RC 2 (05/23/2012):
- #1302406 by Steven Jones: Fixed autoload problem during installation.
- #1340244 by drunken monkey, alanomaly: Added more helpful error messages.
Search API Solr search 1.0, RC 1 (11/10/2011):
Search API Solr Search 1.0, RC 1 (2011-11-10):
----------------------------------------------
- #1308638 by drunken monkey: Adapted to new structure of field settings.
- #1308498 by zenlan, drunken monkey: Added flexibility for facet fields.
- #1319544 by drunken monkey: Fixed never delete contents of read-only indexes.
- #1309650 by jonhattan, drunken monkey: Added support for the Libraries API.
Search API Solr search 1.0, Beta 4 (09/08/2011):
Search API Solr Search 1.0, Beta 4 (2011-09-08):
------------------------------------------------
- #1230536 by thegreat, drunken monkey: Added support for OR facets.
- #1184002 by drunken monkey: Fixed support of the latest SolrPhpClient version.
@@ -181,7 +233,7 @@ Search API Solr search 1.0, Beta 4 (09/08/2011):
- #1184002 by drunken monkey: Fixed INSTALL.txt to reflect that the module
doesn't work with the latest Solr PHP Client version.
Search API Solr search 1.0, Beta 3 (06/06/2011):
Search API Solr Search 1.0, Beta 3 (2011-06-06):
------------------------------------------------
- #1111852 by miiimooo, drunken monkey: Added a 'More like this' feature.
- #1153306 by JoeMcGuire, drunken monkey: Added spellchecking support.
@@ -191,7 +243,7 @@ Search API Solr search 1.0, Beta 3 (06/06/2011):
- #1110820 by becw, drunken monkey: Added support for the Luke request handler.
- #1095956 by drunken monkey: Added Solr-specific index alter hook.
Search API Solr search 1.0, Beta 2 (03/04/2011):
Search API Solr Search 1.0, Beta 2 (2011-03-04):
------------------------------------------------
- #1071894 by drunken monkey: Fixed incorrect handling of boolean facets.
- #1071796: Add additional help for Solr-specific extensions.
@@ -204,7 +256,7 @@ Search API Solr search 1.0, Beta 2 (03/04/2011):
- #915174: Remove unnecessary files[] declarations from .info file.
- #984134: Add Solr-specific query alter hooks.
Search API Solr search 1.0, Beta 1 (11/29/2010):
Search API Solr Search 1.0, Beta 1 (2010-11-29):
------------------------------------------------
Basic functionality is in place and quite well-tested, including support for
facets and for multi-index searches.

View File

@@ -1,72 +0,0 @@
Setting up Solr
---------------
In order for this module to work, you will first need to set up a Solr server.
For this, you can either purchase a server from a web Solr hosts or set up your
own Solr server on your web server (if you have the necessary rights to do so).
If you want to use a hosted solution, a number of companies are listed on the
module's project page [1]. Otherwise, please follow the instructions below.
A more detailed set of instructions is available at [2].
[1] https://drupal.org/project/search_api_solr
[2] https://drupal.org/node/1999310
As a pre-requisite for running your own Solr server, you'll need Java 6 or
higher.
Download the latest version of Solr 4.x from [3] and unpack the archive
somewhere outside of your web server's document tree.
[3] http://www.apache.org/dyn/closer.cgi/lucene/solr/
This module also supports Solr 3.x. For better performance and more features,
4.x should be used, though.
For small websites, using the example application, located in $SOLR/example/,
usually suffices. In any case, you can use it for developing and testing. The
following instructions will assume you are using the example application,
otherwise you should be able to substitute the corresponding paths.
CAUTION! For production sites, it is vital that you somehow prevent outside
access to the Solr server. Otherwise, attackers could read, corrupt or delete
all your indexed data. Using the example server WON'T prevent this by default.
If it is available, the probably easiest way of preventing this is to disable
outside access to the ports used by Solr through your server's network
configuration or through the use of a firewall.
Other options include adding basic HTTP authentication or renaming the solr/
directory to a random string of characters and using that as the path.
Before starting the Solr server you will have to make sure it uses the proper
configuration files. These are located in the solr-conf/ directory in this
module, in a sub-directory according to the Solr version you are using. Copy all
the files from that directory into Solr's configuration directory
($SOLR/example/solr/collection1/conf/ in case of the 4.x example application),
after backing up all files that would be overwritten.
NOTE: The mapping-ISOLatin1Accent.txt is only included in the module for
completeness' sake, as it is required to start the Solr server. It will be
usually advisable to just use the file of the example application in this case,
though, as it contains really useful definitions, while the file provided with
this module is empty, apart from some documentation. For licensing reasons, it
is not possible for us to include the definitions in the example config file in
the copy this module provides.
You can then start Solr. For the example application, go to $SOLR/example/ and
issue the following command (assuming Java is correctly installed):
java -jar start.jar &
Afterwards, go to [4] in your web browser to ensure Solr is running correctly.
[4] http://localhost:8983/solr/
You can then enable this module and create a new server, using the "Solr search"
service class. Enter the hostname, port and path corresponding to your Solr
server in the appropriate fields. The default values already correspond to the
example application, so you won't have to change the values if you use that.
If you are using HTTP Authentication to protect your Solr server you also have
to provide the appropriate user and password here.
NOTE: For Solr 4.x, the server's path should also contain the Solr core name.
E.g., when using the example application unchanged, set the path to
"/solr/collection1" instead of "/solr".

View File

@@ -2,12 +2,10 @@ Solr search
-----------
This module provides an implementation of the Search API which uses an Apache
Solr search server for indexing and searching. Before enabling or using this
module, you'll have to follow the instructions given in INSTALL.txt first.
Solr search server for indexing and searching. You can find detailed
instructions for setting up Solr in the module's handbook [1].
For more detailed documentation, see the handbook [1].
[1] https://drupal.org/node/1999280
[1] https://www.drupal.org/node/1999280
Supported optional features
---------------------------
@@ -139,6 +137,11 @@ Hidden variables
what you are doing. Old indexed items will be lost when the hash is changed
and all items will have to be reindexed. Can only contain alphanumeric
characters.
- search_api_solr_highlight_prefix (default: "tm_")
The prefix of Solr fields for which field-level highlighting will be enabled.
Since the prefix of fields is used to determine the field type (by default),
this lets you enable highlighting for other field types. By default,
highlighting will be possible for all fulltext fields.
[8] http://wiki.apache.org/solr/UpdateXmlMessages#A.22commit.22_and_.22optimize.22

View File

@@ -57,7 +57,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
protected $request_handler = NULL;
/**
* Overrides SearchApiAbstractService::configurationForm().
* {@inheritdoc}
*/
public function configurationForm(array $form, array &$form_state) {
if ($this->options) {
@@ -176,6 +176,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
'#type' => 'textfield',
'#title' => t('Username'),
'#default_value' => $options['http_user'],
// This prefix with no-op text and password field will keep most browsers
// from autocompleting these fields, which is hardly ever what the user
// wants.
'#prefix' => '<input type="text" style="display:none" /><input type="password" style="display:none" />',
);
$form['http']['http_pass'] = array(
'#type' => 'password',
@@ -222,9 +226,9 @@ class SearchApiSolrService extends SearchApiAbstractService {
'#description' => t('Specify the Solr version manually in case it cannot be retrived automatically. The version can be found in the Solr admin interface under "Solr Specification Version" or "solr-spec"'),
'#options' => array(
'' => t('Determine automatically'),
'1' => '1.4',
'3' => '3.x',
'4' => '4.x',
'5' => '5.x',
),
'#default_value' => $options['solr_version'],
);
@@ -271,7 +275,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
/**
* Overrides SearchApiAbstractService::configurationFormValidate().
* {@inheritdoc}
*/
public function configurationFormValidate(array $form, array &$values, array &$form_state) {
if (isset($values['port']) && (!is_numeric($values['port']) || $values['port'] < 0 || $values['port'] > 65535)) {
@@ -280,7 +284,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
/**
* Overrides SearchApiAbstractService::configurationFormSubmit().
* {@inheritdoc}
*/
public function configurationFormSubmit(array $form, array &$values, array &$form_state) {
// Since the form is nested into another, we can't simply use #parents for
@@ -321,6 +325,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
'search_api_spellcheck',
'search_api_data_type_location',
'search_api_data_type_geohash',
'search_api_random_sort',
));
if (isset($supported[$feature])) {
return TRUE;
@@ -428,8 +433,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
$status = 'error';
}
elseif (substr($stats_summary['@schema_version'], 0, 9) != 'drupal-4.') {
$variables['@url'] = url(drupal_get_path('module', 'search_api_solr') . '/INSTALL.txt');
$message = t('You are using an incompatible schema.xml configuration file. Please follow the instructions in the <a href="@url">INSTALL.txt</a> file for setting up Solr.', $variables);
$variables['@url'] = url('https://www.drupal.org/node/1999310');
$message = t('You are using an incompatible schema.xml configuration file. Please follow the instructions in <a href="@url">the handbook</a> for setting up Solr.', $variables);
drupal_set_message($message, 'error');
$status = 'error';
}
@@ -494,7 +499,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
/**
* Overrides SearchApiAbstractService::addIndex().
* {@inheritdoc}
*/
public function addIndex(SearchApiIndex $index) {
if (module_exists('search_api_multi') && module_exists('search_api_views')) {
@@ -503,42 +508,39 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
/**
* Overrides SearchApiAbstractService::fieldsUpdated().
* {@inheritdoc}
*/
public function fieldsUpdated(SearchApiIndex $index) {
if (module_exists('search_api_multi') && module_exists('search_api_views')) {
views_invalidate_cache();
}
return TRUE;
// Find out if anything changed enough to need re-indexing.
$old_fields = isset($index->original->options['fields']) ? $index->original->options['fields'] : array();
$new_fields = isset($index->options['fields']) ? $index->options['fields'] : array();
if (!$old_fields && !$new_fields) {
return FALSE;
}
if (array_diff_key($old_fields, $new_fields) || array_diff_key($new_fields, $old_fields)) {
return TRUE;
}
$old_field_names = $this->getFieldNames($index->original, TRUE);
$new_field_names = $this->getFieldNames($index, TRUE);
return $old_field_names != $new_field_names;
}
/**
* Overrides SearchApiAbstractService::removeIndex().
* {@inheritdoc}
*/
public function removeIndex($index) {
if (module_exists('search_api_multi') && module_exists('search_api_views')) {
views_invalidate_cache();
}
$index_id = is_object($index) ? $index->machine_name : $index;
// Only delete the index's data if the index isn't read-only.
if (!is_object($index) || empty($index->read_only)) {
$this->connect();
$index_id = $this->getIndexId($index_id);
// Since the index ID we use for indexing can contain arbitrary
// prefixes, we have to escape it for use in the query.
$index_id = call_user_func(array($this->connection_class, 'phrase'), $index_id);
$query = "index_id:$index_id";
if (!empty($this->options['site_hash'])) {
// We don't need to escape the site hash, as that consists only of
// alphanumeric characters.
$query .= ' hash:' . search_api_solr_site_hash();
}
$this->solr->deleteByQuery($query);
}
parent::removeIndex($index);
}
/**
* Implements SearchApiServiceInterface::indexItems().
* {@inheritdoc}
*/
public function indexItems(SearchApiIndex $index, array $items) {
$documents = array();
@@ -569,7 +571,9 @@ class SearchApiSolrService extends SearchApiAbstractService {
$doc->setField('site', $base_urls[$lang]);
}
// Now add all fields contained in the item, with dynamic fields.
// Now add all fields contained in the item, with dynamic fields. Also,
// gather the contents of all text fields to also add them to "content".
$text_content = '';
foreach ($item as $key => $field) {
// If the field is not known for the index, something weird has
// happened. We refuse to index the items and hope that the others are
@@ -585,8 +589,9 @@ class SearchApiSolrService extends SearchApiAbstractService {
$doc = NULL;
break;
}
$this->addIndexField($doc, $fields[$key], $field['value'], $field['type']);
$text_content[] = $this->addIndexField($doc, $fields[$key], $field['value'], $field['type']);
}
$doc->setField('content', implode("\n\n", array_filter($text_content)));
if ($doc) {
$documents[] = $doc;
@@ -643,6 +648,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
$ret = array(
'search_api_id' => 'item_id',
'search_api_relevance' => 'score',
'search_api_random' => 'random',
);
// Add the names of any fields configured on the index.
@@ -692,30 +698,32 @@ class SearchApiSolrService extends SearchApiAbstractService {
* is the same as specified in SearchApiServiceInterface::indexItems().
*/
protected function addIndexField(SearchApiSolrDocument $doc, $key, $value, $type, $multi_valued = FALSE) {
$text_content = '';
// Don't index empty values (i.e., when field is missing).
if (!isset($value)) {
return;
return $text_content;
}
if (search_api_is_list_type($type)) {
$type = substr($type, 5, -1);
foreach ($value as $v) {
$this->addIndexField($doc, $key, $v, $type, TRUE);
$text_content .= $this->addIndexField($doc, $key, $v, $type, TRUE) . "\n\n";
}
return;
return trim($text_content);
}
switch ($type) {
case 'tokens':
foreach ($value as $v) {
$text_content .= $v['value'] . ' ';
$doc->addField($key, $v['value']);
}
return;
return trim($text_content);
case 'boolean':
$value = $value ? 'true' : 'false';
break;
case 'date':
$value = is_numeric($value) ? (int) $value : strtotime($value);
if ($value === FALSE) {
return;
return $text_content;
}
$value = format_date($value, 'custom', self::SOLR_DATE_FORMAT, 'UTC');
break;
@@ -732,6 +740,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
else {
$doc->setField($key, $value);
}
if (search_api_is_text_type($type)) {
$text_content = $value;
}
return $text_content;
}
/**
@@ -764,6 +776,17 @@ class SearchApiSolrService extends SearchApiAbstractService {
*
* It is up to the caller to ensure $ids is a valid query when the method is
* called in this fashion.
*
* @param array|string $ids
* Either an array containing the ids of the items that should be deleted,
* or 'all' if all items should be deleted. Other formats might be
* recognized by implementing classes, but these are not standardized.
* @param SearchApiIndex $index
* The index from which items should be deleted, or NULL if all indexes on
* this server should be cleared (then, $ids has to be 'all').
*
* @throws SearchApiException
* If an error occurred while trying to delete the items.
*/
public function deleteItems($ids = 'all', SearchApiIndex $index = NULL) {
$this->connect();
@@ -790,13 +813,13 @@ class SearchApiSolrService extends SearchApiAbstractService {
if ($ids != 'all') {
$query[] = $query ? "($ids)" : $ids;
}
$this->solr->deleteByQuery($query ? implode(' ', $query) : '*:*');
$this->solr->deleteByQuery($query ? implode(' AND ', $query) : '*:*');
}
$this->scheduleCommit();
}
/**
* Implements SearchApiServiceInterface::search().
* {@inheritdoc}
*/
public function search(SearchApiQueryInterface $query) {
$time_method_called = microtime(TRUE);
@@ -820,10 +843,12 @@ class SearchApiSolrService extends SearchApiAbstractService {
$options = $query->getOptions();
$search_fields = $query->getFields();
// Get the index fields to be able to retrieve boosts.
$index_fields = $index->getFields();
$index_fields = $index->getFields() + array(
'search_api_relevance' => array('type' => 'decimal', 'indexed' => TRUE),
'search_api_id' => array('type' => 'integer', 'indexed' => TRUE),
);
$qf = array();
foreach ($search_fields as $f) {
$boost = '';
$boost = isset($index_fields[$f]['boost']) ? '^' . $index_fields[$f]['boost'] : '';
$qf[] = $fields[$f] . $boost;
}
@@ -845,6 +870,17 @@ class SearchApiSolrService extends SearchApiAbstractService {
if (substr($f, 0, 3) == 'ss_') {
$f = 'sort_' . substr($f, 3);
}
// The default Solr schema provides a virtual field named "random_SEED"
// that can be used to randomly sort the results; the field is available
// only at query-time.
if ($field == 'search_api_random') {
$params = $query->getOption('search_api_random_sort', array());
// Random seed: getting the value from parameters or computing a new one.
$seed = !empty($params['seed']) ? $params['seed'] : mt_rand();
$f = 'random_' . $seed;
}
$order = strtolower($order);
$sort[$field] = "$f $order";
}
@@ -862,11 +898,16 @@ class SearchApiSolrService extends SearchApiAbstractService {
$mlt_params['qt'] = 'mlt';
// The fields to look for similarities in.
$mlt_fl = array();
// Solr 4 (before 4.6) has a bug which results in numeric fields not being
// supported in MLT queries.
$mlt_no_numeric_fields = FALSE;
if ($version == 4) {
$system_info = $this->solr->getSystemInfo();
$mlt_no_numeric_fields = !isset($system_info->lucene->{'solr-spec-version'}) || version_compare($system_info->lucene->{'solr-spec-version'}, '4.6.0', '<');
}
foreach($mlt['fields'] as $f) {
// Solr 4 has a bug which results in numeric fields not being supported
// in MLT queries.
// Date fields don't seem to be supported at all.
if ($fields[$f][0] === 'd' || ($version == 4 && in_array($fields[$f][0], array('i', 'f')))) {
if ($fields[$f][0] === 'd' || ($mlt_no_numeric_fields && in_array($fields[$f][0], array('i', 'f')))) {
continue;
}
$mlt_fl[] = $fields[$f];
@@ -879,18 +920,40 @@ class SearchApiSolrService extends SearchApiAbstractService {
$id = $this->createId($index_id, $mlt['id']);
$id = call_user_func(array($this->connection_class, 'phrase'), $id);
$keys = 'id:' . $id;
// In (early versions of) Solr 5, facets aren't supported with MLT.
if ($version >= 5) {
$facet_params = array();
}
}
// Handle spatial filters.
if ($spatials = $query->getOption('search_api_location')) {
foreach ($spatials as $i => $spatial) {
if (empty($spatial['field']) || empty($spatial['lat']) || empty($spatial['lon'])) {
// Spatial options all need a field to do anything.
if (!isset($spatial['field'])) {
continue;
}
unset($radius);
$field = $fields[$spatial['field']];
$escaped_field = SearchApiSolrConnection::escapeFieldName($field);
// If proper bbox coordinates were given use them to filter.
if (isset($spatial['bbox'])) {
if ($version >= 4) {
$bbox = $spatial['bbox'];
$fq[] = $escaped_field . ':[' . (float) $bbox['bottom'] . ',' . (float) $bbox['left'] . ' TO ' . (float) $bbox['top'] . ',' . (float) $bbox['right'] . ']';
}
else {
$warnings[] = t('Filtering by a bounding box is not supported in Solr versions below 4.');
}
}
// Everything other than a bounding box filter requires a point, so stop
// here (for this option) if "lat" and "lon" aren't both set.
if (!isset($spatial['lat']) || !isset($spatial['lon'])) {
continue;
}
$point = ((float) $spatial['lat']) . ',' . ((float) $spatial['lon']);
// Prepare the filter settings.
@@ -1032,6 +1095,18 @@ class SearchApiSolrService extends SearchApiAbstractService {
if (substr($f, 0, 3) == 'ss_') {
$f = 'sort_' . substr($f, 3);
}
// The default Solr schema provides a virtual field named
// "random_SEED" that can be used to randomly sort the results;
// the field is available only at query-time.
if ($group_sort_field == 'search_api_random') {
$params = $query->getOption('search_api_random_sort', array());
// Random seed: getting the value from parameters or computing a
// new one.
$seed = !empty($params['seed']) ? $params['seed'] : mt_rand();
$f = 'random_' . $seed;
}
$order = strtolower($order);
$group_params['group.sort'][] = $f . ' ' . $order;
}
@@ -1275,8 +1350,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
$output = '';
if (!empty($this->options['excerpt']) && !empty($response->highlighting->$id->spell)) {
foreach ($response->highlighting->$id->spell as $snippet) {
if (!empty($this->options['excerpt']) && !empty($response->highlighting->$id->content)) {
foreach ($response->highlighting->$id->content as $snippet) {
$snippet = strip_tags($snippet);
$snippet = preg_replace('/^.*>|<.*$/', '', $snippet);
$snippet = $this->formatHighlighting($snippet);
@@ -1288,8 +1363,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
}
if (!empty($this->options['highlight_data'])) {
$prefix = variable_get('search_api_solr_highlight_prefix', 'tm_');
$prefix_length = strlen($prefix);
foreach ($field_mapping as $search_api_property => $solr_property) {
if (substr($solr_property, 0, 3) == 'tm_' && !empty($response->highlighting->$id->$solr_property)) {
if (substr($solr_property, 0, $prefix_length) == $prefix && !empty($response->highlighting->$id->$solr_property)) {
// Contrary to above, we here want to preserve HTML, so we just
// replace the [HIGHLIGHT] tags with the appropriate format.
$fields[$search_api_property] = $this->formatHighlighting($response->highlighting->$id->$solr_property);
@@ -1497,6 +1574,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
protected function createFilterQueries(SearchApiQueryFilterInterface $filter, array $solr_fields, array $fields) {
$or = $filter->getConjunction() == 'OR';
$fq = array();
$prefix = '';
foreach ($filter->getFilters() as $f) {
if (is_array($f)) {
if (!isset($fields[$f[0]])) {
@@ -1508,10 +1586,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
elseif ($f instanceof SearchApiQueryFilterInterface) {
$q = $this->createFilterQueries($f, $solr_fields, $fields);
if ($filter->getConjunction() != $f->getConjunction()) {
if ($filter->getConjunction() != $f->getConjunction() && count($q) > 1) {
// $or == TRUE means the nested filter has conjunction AND, and vice versa
$sep = $or ? ' ' : ' OR ';
$fq[] = count($q) == 1 ? reset($q) : '((' . implode(')' . $sep . '(', $q) . '))';
$fq[] = '((' . implode(')' . $sep . '(', $q) . '))';
}
else {
$fq = array_merge($fq, $q);
@@ -1520,15 +1598,20 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
if (method_exists($filter, 'getTags')) {
foreach ($filter->getTags() as $tag) {
$tag = "{!tag=$tag}";
foreach ($fq as $i => $filter) {
$fq[$i] = $tag . $filter;
}
$prefix = "{!tag=$tag}";
// We can only apply one tag per filter.
break;
}
}
return ($or && count($fq) > 1) ? array('((' . implode(') OR (', $fq) . '))') : $fq;
if ($or && count($fq) > 1) {
$fq = array('((' . implode(') OR (', $fq) . '))');
}
if ($prefix) {
foreach ($fq as $i => $filter) {
$fq[$i] = $prefix . $filter;
}
}
return $fq;
}
/**
@@ -1550,7 +1633,6 @@ class SearchApiSolrService extends SearchApiAbstractService {
if ($value === NULL) {
return ($operator == '=' ? '*:* AND -' : '') . "$field:[* TO *]";
}
$value = trim($value);
$value = $this->formatFilterValue($value, search_api_extract_inner_type($field_info['type']));
switch ($operator) {
case '<>':
@@ -1584,6 +1666,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
$value = format_date($value, 'custom', self::SOLR_DATE_FORMAT, 'UTC');
break;
case 'text':
return '(' . call_user_func(array($this->connection_class, 'escape'), $value) . ')';
}
return call_user_func(array($this->connection_class, 'phrase'), $value);
}
@@ -1652,7 +1736,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
if (!empty($this->options['excerpt']) || !empty($this->options['highlight_data'])) {
$highlight_params['hl'] = 'true';
$highlight_params['hl.fl'] = 'spell';
$highlight_params['hl.fl'] = 'content';
$highlight_params['hl.simple.pre'] = '[HIGHLIGHT]';
$highlight_params['hl.simple.post'] = '[/HIGHLIGHT]';
$highlight_params['hl.snippets'] = 3;
@@ -1661,17 +1745,18 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
if (!empty($this->options['highlight_data'])) {
$highlight_params['hl.fl'] = 'tm_*';
$highlight_params['hl.fl'] = variable_get('search_api_solr_highlight_prefix', 'tm_') . '*';
$highlight_params['hl.snippets'] = 1;
$highlight_params['hl.fragsize'] = 0;
if (!empty($this->options['excerpt'])) {
// If we also generate a "normal" excerpt, set the settings for the
// "spell" field (which we use to generate the excerpt) back to the
// "content" field (which we use to generate the excerpt) back to the
// above values.
$highlight_params['f.spell.hl.snippets'] = 3;
$highlight_params['f.spell.hl.fragsize'] = 70;
$highlight_params['f.content.hl.snippets'] = 3;
$highlight_params['f.content.hl.fragsize'] = 70;
// It regrettably doesn't seem to be possible to set hl.fl to several
// values, if one contains wild cards (i.e., "t_*,spell" wouldn't work).
// values, if one contains wild cards (i.e., "t_*,content" wouldn't
// work).
$highlight_params['hl.fl'] = '*';
}
}
@@ -1831,6 +1916,14 @@ class SearchApiSolrService extends SearchApiAbstractService {
$this->setRequestHandler($this->request_handler, $call_args);
}
$second_pass = !isset($this->options['autocorrect_suggest_words']) || $this->options['autocorrect_suggest_words'];
$alter_data = array(
'search' => $search,
'query' => $query,
'incomplete_key' => $incomplete_key,
'user_input' => $user_input,
);
for ($i = 0; $i < ($second_pass ? 2 : 1); ++$i) {
try {
// Send search request
@@ -1839,6 +1932,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
$this->preQuery($call_args, $query);
$response = $this->solr->search($keys, $params, $http_method);
$alter_data['responses'][] = $response;
if (!empty($response->spellcheck->suggestions)) {
$replace = array();
foreach ($response->spellcheck->suggestions as $word => $data) {
@@ -1927,9 +2022,11 @@ class SearchApiSolrService extends SearchApiAbstractService {
}
// Change parameters for second query.
unset($params['facet.prefix']);
$keys = trim ($keys . ' ' . $incomplete_key);
$keys = trim($keys . ' ' . $incomplete_key);
}
drupal_alter('search_api_solr_autocomplete_suggestions', $suggestions, $alter_data);
return $suggestions;
}
@@ -1985,7 +2082,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
$search_fields = $query->getFields();
$qf = array();
foreach ($search_fields as $f) {
$qf[] = $solr_fields[$f];
$boost = isset($fields[$f]['boost']) ? '^' . $fields[$f]['boost'] : '';
$qf[] = $solr_fields[$f] . $boost;
}
// Extract filters
@@ -1994,8 +2092,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
// Restrict search to searched indexes.
$index_filter = array();
$indexes = array();
foreach ($query->getIndexes() as $index) {
$index_id = $this->getIndexId($index->machine_name);
$indexes[$index_id] = $index;
$index_filter[] = 'index_id:' . call_user_func(array($this->connection_class, 'phrase'), $index_id);
}
$fq[] = implode(' OR ', $index_filter);
@@ -2050,6 +2150,9 @@ class SearchApiSolrService extends SearchApiAbstractService {
if (!empty($highlight_params)) {
$params += $highlight_params;
}
if (!empty($this->options['retrieve_data'])) {
$params['fl'] = '*,score';
}
// Retrieve http method from server options.
$http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
@@ -2074,16 +2177,44 @@ class SearchApiSolrService extends SearchApiAbstractService {
$results['results'] = array();
$tmp = array();
foreach ($response->response->docs as $id => $doc) {
if (isset($indexes[$doc->index_id])) {
$index = $indexes[$doc->index_id];
}
else {
$index = new SearchApiIndex(array('machine_name' => $doc->index_id));
}
$fields = $this->getFieldNames($index);
$field_options = $index->options['fields'];
$result = array(
'id' => $doc->item_id,
'id' => NULL,
'index_id' => $doc->index_id,
'score' => $doc->score,
'score' => NULL,
'fields' => array(),
);
$solr_id = $this->createId($doc->index_id, $result['id']);
$excerpt = $this->getExcerpt($response, $solr_id, $tmp, array());
$solr_id = $this->createId($doc->index_id, $doc->item_id);
foreach ($fields as $search_api_property => $solr_property) {
if (isset($doc->{$solr_property})) {
$result['fields'][$search_api_property] = $doc->{$solr_property};
// Date fields need some special treatment to become valid date values
// (i.e., timestamps) again.
if (isset($field_options[$search_api_property]['type'])
&& $field_options[$search_api_property]['type'] == 'date'
&& preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/', $result['fields'][$search_api_property])) {
$result['fields'][$search_api_property] = strtotime($result['fields'][$search_api_property]);
}
}
}
$excerpt = $this->getExcerpt($response, $solr_id, $result['fields'], $fields);
if ($excerpt) {
$result['excerpt'] = $excerpt;
}
// We can find the item id and score in the special 'search_api_*'
// properties. Mappings are provided for these properties in
// SearchApiSolrService::getFieldNames().
$result['id'] = $result['fields']['search_api_id'];
$result['score'] = $result['fields']['search_api_relevance'];
$results['results'][$id] = $result;
}

View File

@@ -224,7 +224,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::ping().
* {@inheritdoc}
*/
public function ping($timeout = 2) {
$start = microtime(TRUE);
@@ -251,28 +251,28 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::setSoftCommit().
* {@inheritdoc}
*/
public function setSoftCommit($soft_commit) {
$this->soft_commit = (bool) $soft_commit;
}
/**
* Implements SearchApiSolrConnectionInterface::getSoftCommit().
* {@inheritdoc}
*/
public function getSoftCommit() {
return $this->soft_commit;
}
/**
* Implements SearchApiSolrConnectionInterface::setStreamContext().
* {@inheritdoc}
*/
public function setStreamContext($stream_context) {
$this->stream_context = $stream_context;
}
/**
* Implements SearchApiSolrConnectionInterface::getStreamContext().
* {@inheritdoc}
*/
public function getStreamContext() {
return $this->stream_context;
@@ -333,6 +333,9 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
/**
* Sets $this->luke with the metadata about the index from admin/luke.
*
* @param int $num_terms
* (optional) The number of "top terms" to return.
*/
protected function setLuke($num_terms = 0) {
if (empty($this->luke[$num_terms])) {
@@ -360,7 +363,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::getFields().
* {@inheritdoc}
*/
public function getFields($num_terms = 0) {
$fields = array();
@@ -371,7 +374,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::getLuke().
* {@inheritdoc}
*/
public function getLuke($num_terms = 0) {
if (!isset($this->luke[$num_terms])) {
@@ -381,7 +384,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::getSolrVersion().
* {@inheritdoc}
*/
public function getSolrVersion() {
// Allow for overrides by the user.
@@ -392,7 +395,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
$system_info = $this->getSystemInfo();
// Get our solr version number
if (isset($system_info->lucene->{'solr-spec-version'})) {
return $system_info->lucene->{'solr-spec-version'}[0];
return (int) $system_info->lucene->{'solr-spec-version'};
}
return 0;
}
@@ -430,7 +433,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::getStats().
* {@inheritdoc}
*/
public function getStats() {
if (!isset($this->stats)) {
@@ -440,7 +443,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::getStatsSummary().
* {@inheritdoc}
*/
public function getStatsSummary() {
$stats = $this->getStats();
@@ -506,7 +509,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::clearCache().
* {@inheritdoc}
*/
public function clearCache() {
if ($cid = $this->getCacheId()) {
@@ -545,7 +548,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::makeServletRequest().
* {@inheritdoc}
*/
public function makeServletRequest($servlet, array $params = array(), array $options = array()) {
// Add default params.
@@ -561,7 +564,19 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Central method for making a GET operation against this Solr Server
* Sends a GET request to the Solr server.
*
* @param string $url
* The URL to which the request should be sent.
* @param array $options
* Additional options for the request, as recognized by
* drupal_http_request().
*
* @return object
* The HTTP response, as returned by drupal_http_request().
*
* @throws SearchApiException
* If an error occurs, either during sending or on the server side.
*/
protected function sendRawGet($url, array $options = array()) {
$options['method'] = 'GET';
@@ -571,7 +586,19 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Central method for making a POST operation against this Solr Server
* Sends a PUT request to the Solr server.
*
* @param string $url
* The URL to which the request should be sent.
* @param array $options
* Additional options for the request, as recognized by
* drupal_http_request().
*
* @return object
* The HTTP response, as returned by drupal_http_request().
*
* @throws SearchApiException
* If an error occurs, either during sending or on the server side.
*/
protected function sendRawPost($url, array $options = array()) {
$options['method'] = 'POST';
@@ -588,6 +615,15 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
* Sends an HTTP request to Solr.
*
* This is just a wrapper around drupal_http_request().
*
* @param string $url
* The URL to which the request should be sent.
* @param array $options
* Additional options for the request, as recognized by
* drupal_http_request().
*
* @return object
* The HTTP response, as returned by drupal_http_request().
*/
protected function makeHttpRequest($url, array $options = array()) {
if (empty($options['method']) || $options['method'] == 'GET' || $options['method'] == 'HEAD') {
@@ -603,6 +639,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
$result = drupal_http_request($url, $options);
$result->status_message = isset($result->status_message) ? $result->status_message : '';
if (!isset($result->code) || $result->code < 0) {
$result->code = 0;
$result->status_message = 'Request failed';
@@ -630,12 +667,12 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::escape().
* {@inheritdoc}
*/
public static function escape($value, $version = 0) {
$replacements = array();
$specials = array('+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', "\\");
$specials = array('+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', "\\", 'AND', 'OR', 'NOT');
// Solr 4.x introduces regular expressions, making the slash also a special
// character.
if ($version >= 4) {
@@ -650,7 +687,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::escapePhrase().
* {@inheritdoc}
*/
public static function escapePhrase($value) {
$replacements['"'] = '\"';
@@ -659,14 +696,14 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::phrase().
* {@inheritdoc}
*/
public static function phrase($value) {
return '"' . self::escapePhrase($value) . '"';
}
/**
* Implements SearchApiSolrConnectionInterface::escapeFieldName().
* {@inheritdoc}
*/
public static function escapeFieldName($value) {
$value = str_replace(':', '\:', $value);
@@ -684,6 +721,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
* Additional query string to append to the URL.
*
* @return string
* The complete URL.
*/
protected function constructUrl($servlet, array $params = array(), $added_query_string = NULL) {
// PHP's built in http_build_query() doesn't give us the format Solr wants.
@@ -703,14 +741,14 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::getBaseUrl().
* {@inheritdoc}
*/
public function getBaseUrl() {
return $this->base_url;
}
/**
* Implements SearchApiSolrConnectionInterface::setBaseUrl().
* {@inheritdoc}
*/
public function setBaseUrl($url) {
$this->base_url = $url;
@@ -718,9 +756,9 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::update().
* {@inheritdoc}
*/
public function update($rawPost, $timeout = FALSE) {
public function update($rawPost, $timeout = 3600) {
if (empty($this->update_url)) {
// Store the URL in an instance variable since many updates may be sent
// via a single instance of this class.
@@ -734,7 +772,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::addDocuments().
* {@inheritdoc}
*/
public function addDocuments(array $documents, $overwrite = NULL, $commitWithin = NULL) {
$attr = '';
@@ -758,21 +796,21 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::commit().
* {@inheritdoc}
*/
public function commit($waitSearcher = TRUE, $timeout = 3600) {
return $this->optimizeOrCommit('commit', $waitSearcher, $timeout);
}
/**
* Implements SearchApiSolrConnectionInterface::deleteById().
* {@inheritdoc}
*/
public function deleteById($id, $timeout = 3600) {
return $this->deleteByMultipleIds(array($id), $timeout);
}
/**
* Implements SearchApiSolrConnectionInterface::deleteByMultipleIds().
* {@inheritdoc}
*/
public function deleteByMultipleIds(array $ids, $timeout = 3600) {
$rawPost = '<delete>';
@@ -786,7 +824,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::deleteByQuery().
* {@inheritdoc}
*/
public function deleteByQuery($rawQuery, $timeout = 3600) {
$rawPost = '<delete><query>' . htmlspecialchars($rawQuery, ENT_NOQUOTES, 'UTF-8') . '</query></delete>';
@@ -795,14 +833,14 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
}
/**
* Implements SearchApiSolrConnectionInterface::optimize().
* {@inheritdoc}
*/
public function optimize($waitSearcher = TRUE, $timeout = 3600) {
return $this->optimizeOrCommit('optimize', $waitSearcher, $timeout);
}
/**
* Sends an commit or optimize command to the Solr server.
* Sends a commit or optimize command to the Solr server.
*
* Will be synchronous unless $waitSearcher is set to FALSE.
*
@@ -900,26 +938,6 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
// search keys here. (With our normal service class, empty keys won't be
// set, but another module using this connection class might do that.)
unset($params['q'], $params['qf']);
// If we have filters set (which will nearly always be the case, since we
// have to filter by index), move them to the q.alt parameter where
// possible.
if (!empty($params['fq'])) {
$qalt = array();
foreach ($params['fq'] as $i => $fq) {
// Tagged and negative filters cannot be moved to q.alt.
if ($fq[0] !== '{' && $fq[0] !== '-') {
$qalt[] = "($fq)";
unset($params['fq'][$i]);
}
}
if ($qalt) {
$params['q.alt'] = implode(' ', $qalt);
}
if (empty($params['fq'])) {
unset($params['fq']);
}
}
}
// Build the HTTP query string. We have our own method for that since PHP's

View File

@@ -158,8 +158,7 @@ interface SearchApiSolrConnectionInterface {
* @param string $rawPost
* The XML document to send to the Solr server's update service.
* @param int|false $timeout
* (optional) Maximum expected duration (in seconds). Defaults to not timing
* out.
* (optional) Maximum expected duration (in seconds).
*
* @return object
* A response object.
@@ -167,7 +166,7 @@ interface SearchApiSolrConnectionInterface {
* @throws SearchApiException
* If an error occurs during the service call
*/
public function update($rawPost, $timeout = FALSE);
public function update($rawPost, $timeout = 3600);
/**
* Adds an array of Solr Documents to the index all at once
@@ -229,7 +228,7 @@ interface SearchApiSolrConnectionInterface {
/**
* Sends a delete request for several documents, based on the document IDs.
*
* @param array $id
* @param array $ids
* The IDs of the documents which should be deleted. Expected to be UTF-8
* encoded.
* @param int|false $timeout
@@ -307,8 +306,8 @@ interface SearchApiSolrConnectionInterface {
*
* @param string $value
* The string to escape.
* @param string $version
* An integer representing major solr version release.
* @param int $version
* An integer representing the major solr version.
*
* @return string
* An escaped string suitable for passing to Solr.

View File

@@ -23,8 +23,10 @@ class SearchApiSpellcheckSolr extends SearchApiSpellcheck {
if (isset($response->spellcheck->suggestions)) {
$suggestions = $response->spellcheck->suggestions;
foreach ($suggestions as $word => $data) {
foreach ($data->suggestion as $suggestion) {
$this->addSuggestion(new SearchApiSpellcheckSuggestion($word, $suggestion));
if (isset($data->suggestion)) {
foreach ($data->suggestion as $suggestion) {
$this->addSuggestion(new SearchApiSpellcheckSuggestion($word, $suggestion));
}
}
}
}

View File

@@ -161,6 +161,24 @@ function search_api_solr_hook_search_api_data_type_info() {
);
}
/**
* Alter autocomplete suggestions returned from Solr servers.
*
* @param array $suggestions
* An array of suggestions to be altered, in the structure documented in
* SearchApiAutocompleteSuggesterInterface::getAutocompleteSuggestions().
* @param array $alter_data
* An associative array of data about the search, with the following keys:
* "search", "query", "incomplete_key", "user_input", which correspond to the
* arguments to SearchApiAutocompleteInterface::getAutocompleteSuggestions();
* and "responses", an array containing the Solr response objects used for
* constructing the suggestions.
*/
function hook_search_api_solr_autocomplete_suggestions_alter(array &$suggestions, array &$alter_data) {
// Always also suggest the original user input.
array_unshift($suggestions, trim($alter_data['user_input']));
}
/**
* @} End of "addtogroup hooks".
*/

View File

@@ -11,9 +11,9 @@ files[] = includes/solr_connection.interface.inc
files[] = includes/solr_field.inc
files[] = includes/spellcheck.inc
; Information added by Drupal.org packaging script on 2014-09-08
version = "7.x-1.6"
; Information added by Drupal.org packaging script on 2016-02-23
version = "7.x-1.9+10-dev"
core = "7.x"
project = "search_api_solr"
datestamp = "1410186051"
datestamp = "1456233244"

View File

@@ -10,7 +10,7 @@
http://wiki.apache.org/solr/SchemaXml
-->
<schema name="drupal-4.2-solr-3.x" version="1.3">
<schema name="drupal-4.3-solr-3.x" version="1.3">
<!-- 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
@@ -211,6 +211,29 @@
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
<analyzer type="multiterm">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="1"
preserveOriginal="1"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldType>
<!-- An unstemmed text field - good if one does not know the language of the field -->
@@ -248,6 +271,25 @@
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="multiterm">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="0"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- Edge N gram type - for example for matching against queries with results

View File

@@ -20,7 +20,7 @@
For more details about configurations options that may appear in
this file, see http://wiki.apache.org/solr/SolrConfigXml.
-->
<config name="drupal-4.2-solr-3.x">
<config name="drupal-4.3-solr-3.x">
<!-- In all configuration below, a prefix of "solr." for class names
is an alias that causes solr to search appropriate packages,
including org.apache.solr.(search|update|request|core|analysis)
@@ -871,6 +871,7 @@
</lst>
<arr name="last-components">
<str>spellcheck</str>
<str>elevator</str>
</arr>
</requestHandler>

View File

@@ -10,7 +10,7 @@
http://wiki.apache.org/solr/SchemaXml
-->
<schema name="drupal-4.2-solr-4.x" version="1.3">
<schema name="drupal-4.3-solr-4.x" version="1.3">
<!-- 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
@@ -211,6 +211,29 @@
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
<analyzer type="multiterm">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="1"
preserveOriginal="1"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldType>
<!-- An unstemmed text field - good if one does not know the language of the field -->
@@ -248,6 +271,25 @@
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="multiterm">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="0"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- Edge N gram type - for example for matching against queries with results

View File

@@ -20,7 +20,7 @@
For more details about configurations options that may appear in
this file, see http://wiki.apache.org/solr/SolrConfigXml.
-->
<config name="drupal-4.2-solr-4.x" >
<config name="drupal-4.3-solr-4.x" >
<!-- In all configuration below, a prefix of "solr." for class names
is an alias that causes solr to search appropriate packages,
including org.apache.solr.(search|update|request|core|analysis)
@@ -880,6 +880,7 @@
</lst>
<arr name="last-components">
<str>spellcheck</str>
<str>elevator</str>
</arr>
</requestHandler>
@@ -1068,10 +1069,17 @@
<lst name="invariants">
<str name="qt">pinkPony</str>
<str name="q">solrpingquery</str>
<str name="omitHeader">false</str>
</lst>
<lst name="defaults">
<str name="echoParams">all</str>
</lst>
<!-- An optional feature of the PingRequestHandler is to configure the
handler with a "healthcheckFile" which can be used to enable/disable
the PingRequestHandler.
relative paths are resolved against the data dir
-->
<!-- <str name="healthcheckFile">server-enabled.txt</str> -->
</requestHandler>
<!-- Echo the request contents back to the client -->

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
This file allows you to boost certain search items to the top of search
results. You can find out an item's ID by searching directly on the Solr
server. The item IDs are in general constructed as follows:
Search API:
$document->id = $index_id . '-' . $item_id;
Apache Solr Search Integration:
$document->id = $site_hash . '/' . $entity_type . '/' . $entity->id;
If you want this file to be automatically re-loaded when a Solr commit takes
place (e.g., if you have an automatic script active which updates elevate.xml
according to newly-indexed data), place it into Solr's data/ directory.
Otherwise, place it with the other configuration files into the conf/
directory.
See http://wiki.apache.org/solr/QueryElevationComponent for more information.
-->
<elevate>
<!-- Example for ranking the node #1 first in searches for "example query": -->
<!--
<query text="example query">
<doc id="default_node_index-1" />
<doc id="7v3jsc/node/1" />
</query>
-->
<!-- Multiple <query> elements can be specified, contained in one <elevate>. -->
<!-- <query text="...">...</query> -->
</elevate>

View File

@@ -0,0 +1,14 @@
# This file contains character mappings for the default fulltext field type.
# The source characters (on the left) will be replaced by the respective target
# characters before any other processing takes place.
# Lines starting with a pound character # are ignored.
#
# For sensible defaults, use the mapping-ISOLatin1Accent.txt file distributed
# with the example application of your Solr version.
#
# Examples:
# "À" => "A"
# "\u00c4" => "A"
# "\u00c4" => "\u0041"
# "æ" => "ae"
# "\n" => " "

View File

@@ -0,0 +1,7 @@
#-----------------------------------------------------------------------
# This file blocks words from being operated on by the stemmer and word delimiter.
&amp;
&lt;
&gt;
&#039;
&quot;

View File

@@ -0,0 +1,693 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
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.
For more information, on how to customize this file, please see
http://wiki.apache.org/solr/SchemaXml
-->
<schema name="drupal-4.3-solr-5.x" version="1.5">
<!-- 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.
1.3: removed optional field compress feature
1.4: autoGeneratePhraseQueries attribute introduced to drive
QueryParser behavior when a single string produces multiple
tokens. Defaults to off for version >= 1.4
1.5: omitNorms defaults to true for primitive field types
(int, float, boolean, string...)
-->
<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"/>
<!-- boolean type: "true" or "false" -->
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="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.
- 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.
-->
<!-- numeric field types that can be sorted, but are not optimized for range queries -->
<fieldType name="integer" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" 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.
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.TrieIntField" sortMissingLast="true"/>
<fieldType name="sfloat" class="solr.TrieFloatField" sortMissingLast="true"/>
<fieldType name="slong" class="solr.TrieLongField" sortMissingLast="true"/>
<fieldType name="sdouble" class="solr.TrieDoubleField" sortMissingLast="true"/>
<!--
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" positionIncrementGap="0"/>
<fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" positionIncrementGap="0"/>
<fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" positionIncrementGap="0"/>
<fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" positionIncrementGap="0"/>
<!--
The ExternalFileField type gets values from an external file instead of the
index. This is useful for data such as rankings that might change frequently
and require different update frequencies than the documents they are
associated with.
-->
<fieldType name="file" keyField="id" defVal="1" stored="false" indexed="false" class="solr.ExternalFileField" valType="float"/>
<!-- 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 TrieDateField javadocs for more information.
Note: For faster range queries, consider the tdate type
-->
<fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0" sortMissingLast="true" omitNorms="true"/>
<!-- A Trie based date field for faster date range queries and date faceting. -->
<fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0"/>
<!-- 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" omitNorms="true" positionIncrementGap="100">
<analyzer>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</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.
Duplicate tokens at the same position (which may result from Stemmed Synonyms or
WordDelim parts) are removed.
-->
<fieldType name="text" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<!-- in this example, we will only use synonyms at query time
<filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
-->
<!-- Case insensitive stop word removal. -->
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="1"
catenateNumbers="1"
catenateAll="0"
splitOnCaseChange="0"
preserveOriginal="1"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
<analyzer type="query">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="0"
preserveOriginal="1"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
<analyzer type="multiterm">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="1"
preserveOriginal="1"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.SnowballPorterFilterFactory" language="English" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldType>
<!-- An unstemmed text field - good if one does not know the language of the field -->
<fieldType name="text_und" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="1"
catenateNumbers="1"
catenateAll="0"
splitOnCaseChange="0"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="0"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="multiterm">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory"
ignoreCase="true"
words="stopwords.txt"
/>
<filter class="solr.WordDelimiterFilterFactory"
protected="protwords.txt"
generateWordParts="1"
generateNumberParts="1"
catenateWords="0"
catenateNumbers="0"
catenateAll="0"
splitOnCaseChange="0"/>
<filter class="solr.LengthFilterFactory" min="2" max="100" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- Edge N gram type - for example for matching against queries with results
KeywordTokenizer leaves input string intact as a single term.
see: http://www.lucidimagination.com/blog/2009/09/08/auto-suggest-from-popular-queries-using-edgengrams/
-->
<fieldType name="edge_n2_kw_text" class="solr.TextField" omitNorms="true" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="25" />
</analyzer>
<analyzer type="query">
<tokenizer class="solr.KeywordTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
<!-- Setup simple analysis for spell checking -->
<fieldType name="textSpell" class="solr.TextField" positionIncrementGap="100">
<analyzer>
<tokenizer class="solr.StandardTokenizerFactory" />
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
<filter class="solr.LengthFilterFactory" min="4" max="20" />
<filter class="solr.LowerCaseFilterFactory" />
<filter class="solr.RemoveDuplicatesTokenFilterFactory" />
</analyzer>
</fieldType>
<!-- This is an example of using the KeywordTokenizer along
With various TokenFilterFactories to produce a sortable field
that does not include some properties of the source text
-->
<fieldType name="sortString" class="solr.TextField" sortMissingLast="true" omitNorms="true">
<analyzer>
<!-- KeywordTokenizer does no actual tokenizing, so the entire
input string is preserved as a single token
-->
<tokenizer class="solr.KeywordTokenizerFactory"/>
<!-- The LowerCase TokenFilter does what you expect, which can be
when you want your sorting to be case insensitive
-->
<filter class="solr.LowerCaseFilterFactory" />
<!-- The TrimFilter removes any leading or trailing whitespace -->
<filter class="solr.TrimFilterFactory" />
<!-- The PatternReplaceFilter gives you the flexibility to use
Java Regular expression to replace any sequence of characters
matching a pattern with an arbitrary replacement string,
which may include back refrences to portions of the orriginal
string matched by the pattern.
See the Java Regular Expression documentation for more
infomation on pattern and replacement string syntax.
http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/package-summary.html
<filter class="solr.PatternReplaceFilterFactory"
pattern="(^\p{Punct}+)" replacement="" replace="all"
/>
-->
</analyzer>
</fieldType>
<!-- 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
or function 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 field name in the request.
-->
<fieldType name="rand" class="solr.RandomSortField" indexed="true" />
<!-- Fulltext type for matching words based on how they sound i.e.,
"phonetic matching".
-->
<fieldType name="phonetic" class="solr.TextField" >
<analyzer>
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.DoubleMetaphoneFilterFactory" inject="false"/>
</analyzer>
</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" />
<!-- This point type indexes the coordinates as separate fields (subFields)
If subFieldType is defined, it references a type, and a dynamic field
definition is created matching *___<typename>. Alternately, if
subFieldSuffix is defined, that is used to create the subFields.
Example: if subFieldType="double", then the coordinates would be
indexed in fields myloc_0___double,myloc_1___double.
Example: if subFieldSuffix="_d" then the coordinates would be indexed
in fields myloc_0_d,myloc_1_d
The subFields are an implementation detail of the fieldType, and end
users normally should not need to know about them.
-->
<fieldType name="point" class="solr.PointType" dimension="2" subFieldType="tdouble"/>
<!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. -->
<fieldType name="location" class="solr.LatLonType" subFieldType="tdouble"/>
<!-- A Geohash is a compact representation of a latitude longitude pair in a single field.
See http://wiki.apache.org/solr/SpatialSearch
-->
<fieldtype name="geohash" class="solr.GeoHashField"/>
<!-- Improved location type which supports advanced functionality like
filtering by polygons or other shapes, indexing shapes, multi-valued
fields, etc.
-->
<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
geo="true" distErrPct="0.025" maxDistErr="0.001" distanceUnits="kilometers" />
<!-- Spatial rectangle (bounding box) field. It supports most spatial predicates, and has
special relevancy modes: score=overlapRatio|area|area2D (local-param to the query). DocValues is recommended for
relevancy. -->
<fieldType name="bbox" class="solr.BBoxField"
geo="true" distanceUnits="kilometers" numberType="_bbox_coord" />
<fieldType name="_bbox_coord" class="solr.TrieDoubleField" precisionStep="8" docValues="true" stored="false"/>
</types>
<!-- Following is a dynamic way to include other types, added by other contrib modules -->
<xi:include href="schema_extra_types.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:fallback></xi:fallback>
</xi:include>
<!-- Valid attributes for fields:
name: mandatory - the name for the field
type: mandatory - the name of a field type from the <types> fieldType
section
indexed: true if this field should be indexed (searchable or sortable)
stored: true if this field should be retrievable
docValues: true if this field should have doc values. Doc values are
useful for faceting, grouping, sorting and function queries. Although not
required, doc values will make the index faster to load, more
NRT-friendly and more memory-efficient. They however come with some
limitations: they are currently only supported by StrField, UUIDField
and all Trie*Fields, and depending on the field type, they might
require the field to be single-valued, be required or have a default
value (check the documentation of the field type you're interested in
for more information)
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.
Norms are omitted for primitive (non-analyzed) types by default.
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.
required: The field is required. It will throw an error if the
value does not exist
default: a value that should be used if no value is specified
when adding a document.
-->
<fields>
<!-- The document id is usually derived from a site-spcific key (hash) and the
entity type and ID like:
Search Api :
The format used is $document->id = $index_id . '-' . $item_id
Apache Solr Search Integration
The format used is $document->id = $site_hash . '/' . $entity_type . '/' . $entity->id;
-->
<field name="id" type="string" indexed="true" stored="true" required="true" />
<!-- Add Solr Cloud version field as mentioned in
http://wiki.apache.org/solr/SolrCloud#Required_Config
-->
<field name="_version_" type="long" indexed="true" stored="true" multiValued="false"/>
<!-- Search Api specific fields -->
<!-- item_id contains the entity ID, e.g. a node's nid. -->
<field name="item_id" type="string" indexed="true" stored="true" />
<!-- index_id is the machine name of the search index this entry belongs to. -->
<field name="index_id" type="string" indexed="true" stored="true" />
<!-- copyField commands copy one field to another at the time a document
is added to the index. It's used either to index the same field differently,
or to add multiple fields to the same field for easier/faster searching. -->
<!-- Since sorting by ID is explicitly allowed, store item_id also in a sortable way. -->
<copyField source="item_id" dest="sort_search_api_id" />
<!-- Apache Solr Search Integration specific fields -->
<!-- entity_id is the numeric object ID, e.g. Node ID, File ID -->
<field name="entity_id" type="long" indexed="true" stored="true" />
<!-- entity_type is 'node', 'file', 'user', or some other Drupal object type -->
<field name="entity_type" type="string" indexed="true" stored="true" />
<!-- bundle is a node type, or as appropriate for other entity types -->
<field name="bundle" type="string" indexed="true" stored="true"/>
<field name="bundle_name" type="string" indexed="true" stored="true"/>
<field name="site" type="string" indexed="true" stored="true"/>
<field name="hash" type="string" indexed="true" stored="true"/>
<field name="url" type="string" indexed="true" stored="true"/>
<!-- label is the default field for a human-readable string for this entity (e.g. the title of a node) -->
<field name="label" type="text" indexed="true" stored="true" termVectors="true" omitNorms="true"/>
<!-- The string version of the title is used for sorting -->
<copyField source="label" dest="sort_label"/>
<!-- content is the default field for full text search - dump crap here -->
<field name="content" type="text" indexed="true" stored="true" termVectors="true"/>
<field name="teaser" type="text" indexed="false" stored="true"/>
<field name="path" type="string" indexed="true" stored="true"/>
<field name="path_alias" type="text" indexed="true" stored="true" termVectors="true" omitNorms="true"/>
<!-- These are the fields that correspond to a Drupal node. The beauty of having
Lucene store title, body, type, etc., is that we retrieve them with the search
result set and don't need to go to the database with a node_load. -->
<field name="tid" type="long" indexed="true" stored="true" multiValued="true"/>
<field name="taxonomy_names" type="text" indexed="true" stored="false" termVectors="true" multiValued="true" omitNorms="true"/>
<!-- Copy terms to a single field that contains all taxonomy term names -->
<copyField source="tm_vid_*" dest="taxonomy_names"/>
<!-- Here, default is used to create a "timestamp" field indicating
when each document was indexed.-->
<field name="timestamp" type="tdate" indexed="true" stored="true" default="NOW" multiValued="false"/>
<!-- This field is used to build the spellchecker index -->
<field name="spell" type="textSpell" indexed="true" stored="true" multiValued="true"/>
<!-- copyField commands copy one field to another at the time a document
is added to the index. It's used either to index the same field differently,
or to add multiple fields to the same field for easier/faster searching. -->
<copyField source="label" dest="spell"/>
<copyField source="content" dest="spell"/>
<copyField source="ts_*" dest="spell"/>
<copyField source="tm_*" dest="spell"/>
<!-- Dynamic field definitions. If a field name is not found, dynamicFields
will be used if the name matches any of the patterns.
RESTRICTION: the glob-like pattern in the name attribute must have
a "*" only at the start or the end.
EXAMPLE: name="*_i" will match any field ending in _i (like myid_i, z_i)
Longer patterns will be matched first. if equal size patterns
both match, the first appearing in the schema will be used. -->
<!-- A set of fields to contain text extracted from HTML tag contents which we
can boost at query time. -->
<dynamicField name="tags_*" type="text" indexed="true" stored="false" omitNorms="true"/>
<!-- For 2 and 3 letter prefix dynamic fields, the 1st letter indicates the data type and
the last letter is 's' for single valued, 'm' for multi-valued -->
<!-- We use long for integer since 64 bit ints are now common in PHP. -->
<dynamicField name="is_*" type="long" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="im_*" type="long" indexed="true" stored="true" multiValued="true"/>
<!-- List of floats can be saved in a regular float field -->
<dynamicField name="fs_*" type="float" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="fm_*" type="float" indexed="true" stored="true" multiValued="true"/>
<!-- List of doubles can be saved in a regular double field -->
<dynamicField name="ps_*" type="double" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="pm_*" type="double" indexed="true" stored="true" multiValued="true"/>
<!-- List of booleans can be saved in a regular boolean field -->
<dynamicField name="bm_*" type="boolean" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="bs_*" type="boolean" indexed="true" stored="true" multiValued="false"/>
<!-- Regular text (without processing) can be stored in a string field-->
<dynamicField name="ss_*" type="string" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="sm_*" type="string" indexed="true" stored="true" multiValued="true"/>
<!-- Normal text fields are for full text - the relevance of a match depends on the length of the text -->
<dynamicField name="ts_*" type="text" indexed="true" stored="true" multiValued="false" termVectors="true"/>
<dynamicField name="tm_*" type="text" indexed="true" stored="true" multiValued="true" termVectors="true"/>
<!-- Unstemmed text fields for full text - the relevance of a match depends on the length of the text -->
<dynamicField name="tus_*" type="text_und" indexed="true" stored="true" multiValued="false" termVectors="true"/>
<dynamicField name="tum_*" type="text_und" indexed="true" stored="true" multiValued="true" termVectors="true"/>
<!-- These text fields omit norms - useful for extracted text like taxonomy_names -->
<dynamicField name="tos_*" type="text" indexed="true" stored="true" multiValued="false" termVectors="true" omitNorms="true"/>
<dynamicField name="tom_*" type="text" indexed="true" stored="true" multiValued="true" termVectors="true" omitNorms="true"/>
<!-- Special-purpose text fields -->
<dynamicField name="tes_*" type="edge_n2_kw_text" indexed="true" stored="true" multiValued="false" omitTermFreqAndPositions="true" />
<dynamicField name="tem_*" type="edge_n2_kw_text" indexed="true" stored="true" multiValued="true" omitTermFreqAndPositions="true" />
<dynamicField name="tws_*" type="text_ws" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="twm_*" type="text_ws" indexed="true" stored="true" multiValued="true"/>
<!-- trie dates are preferred, so give them the 2 letter prefix -->
<dynamicField name="ds_*" type="tdate" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="dm_*" type="tdate" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="its_*" type="tlong" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="itm_*" type="tlong" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="fts_*" type="tfloat" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="ftm_*" type="tfloat" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="pts_*" type="tdouble" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="ptm_*" type="tdouble" indexed="true" stored="true" multiValued="true"/>
<!-- Binary fields can be populated using base64 encoded data. Useful e.g. for embedding
a small image in a search result using the data URI scheme -->
<dynamicField name="xs_*" type="binary" indexed="false" stored="true" multiValued="false"/>
<dynamicField name="xm_*" type="binary" indexed="false" stored="true" multiValued="true"/>
<!-- In rare cases a date rather than tdate is needed for sortMissingLast -->
<dynamicField name="dds_*" type="date" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="ddm_*" type="date" indexed="true" stored="true" multiValued="true"/>
<!-- Sortable fields, good for sortMissingLast support &
We use long for integer since 64 bit ints are now common in PHP. -->
<dynamicField name="iss_*" type="slong" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="ism_*" type="slong" indexed="true" stored="true" multiValued="true"/>
<!-- In rare cases a sfloat rather than tfloat is needed for sortMissingLast -->
<dynamicField name="fss_*" type="sfloat" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="fsm_*" type="sfloat" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="pss_*" type="sdouble" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="psm_*" type="sdouble" indexed="true" stored="true" multiValued="true"/>
<!-- In case a 32 bit int is really needed, we provide these fields. 'h' is mnemonic for 'half word', i.e. 32 bit on 64 arch -->
<dynamicField name="hs_*" type="integer" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="hm_*" type="integer" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="hss_*" type="sint" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="hsm_*" type="sint" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="hts_*" type="tint" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="htm_*" type="tint" indexed="true" stored="true" multiValued="true"/>
<!-- Unindexed string fields that can be used to store values that won't be searchable -->
<dynamicField name="zs_*" type="string" indexed="false" stored="true" multiValued="false"/>
<dynamicField name="zm_*" type="string" indexed="false" stored="true" multiValued="true"/>
<!-- Fields for location searches.
http://wiki.apache.org/solr/SpatialSearch#geodist_-_The_distance_function -->
<dynamicField name="points_*" type="point" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="pointm_*" type="point" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="locs_*" type="location" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="locm_*" type="location" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="geos_*" type="geohash" indexed="true" stored="true" multiValued="false"/>
<dynamicField name="geom_*" type="geohash" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="bboxs_*" type="bbox" indexed="true" stored="true" multiValued="false" />
<dynamicField name="bboxm_*" type="bbox" indexed="true" stored="true" multiValued="true" />
<dynamicField name="rpts_*" type="location_rpt" indexed="true" stored="true" multiValued="false" />
<dynamicField name="rptm_*" type="location_rpt" indexed="true" stored="true" multiValued="true" />
<!-- Special fields for Solr 5 functionality. -->
<dynamicField name="phons_*" type="phonetic" indexed="true" stored="true" multiValued="false" />
<dynamicField name="phonm_*" type="phonetic" indexed="true" stored="true" multiValued="true" />
<!-- External file fields -->
<dynamicField name="eff_*" type="file"/>
<!-- Sortable version of the dynamic string field -->
<dynamicField name="sort_*" type="sortString" indexed="true" stored="false"/>
<copyField source="ss_*" dest="sort_*"/>
<!-- A random sort field -->
<dynamicField name="random_*" type="rand" indexed="true" stored="true"/>
<!-- This field is used to store access information (e.g. node access grants), as opposed to field data -->
<dynamicField name="access_*" type="integer" indexed="true" stored="false" multiValued="true"/>
<!-- The following causes solr 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>
<!-- Following is a dynamic way to include other fields, added by other contrib modules -->
<xi:include href="schema_extra_fields.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:fallback></xi:fallback>
</xi:include>
<!-- 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>
<!-- Similarity is the scoring routine for each document vs. a query.
A custom Similarity or SimilarityFactory may be specified here, but
the default is fine for most applications.
For more info: http://wiki.apache.org/solr/SchemaXml#Similarity
-->
<!--
<similarity class="com.example.solr.CustomSimilarityFactory">
<str name="paramkey">param value</str>
</similarity>
-->
<!-- DEPRECATED: The defaultSearchField is consulted by various query parsers
when parsing a query string that isn't explicit about the field. Machine
(non-user) generated queries are best made explicit, or they can use the
"df" request parameter which takes precedence over this.
Note: Un-commenting defaultSearchField will be insufficient if your request
handler in solrconfig.xml defines "df", which takes precedence. That would
need to be removed.
<defaultSearchField>content</defaultSearchField> -->
<!-- DEPRECATED: The defaultOperator (AND|OR) is consulted by various query
parsers when parsing a query string to determine if a clause of the query
should be marked as required or optional, assuming the clause isn't already
marked by some operator. The default is OR, which is generally assumed so it
is not a good idea to change it globally here. The "q.op" request parameter
takes precedence over this.
<solrQueryParser defaultOperator="OR"/> -->
</schema>

View File

@@ -0,0 +1,23 @@
<fields>
<!--
Example: Adding German dynamic field types to our Solr Schema.
If you enable this, make sure you have a folder called lang containing
stopwords_de.txt and synonyms_de.txt.
This also requires to enable the content in schema_extra_types.xml.
-->
<!--
<field name="label_de" type="text_de" indexed="true" stored="true" termVectors="true" omitNorms="true"/>
<field name="content_de" type="text_de" indexed="true" stored="true" termVectors="true"/>
<field name="teaser_de" type="text_de" indexed="false" stored="true"/>
<field name="path_alias_de" type="text_de" indexed="true" stored="true" termVectors="true" omitNorms="true"/>
<field name="taxonomy_names_de" type="text_de" indexed="true" stored="false" termVectors="true" multiValued="true" omitNorms="true"/>
<field name="spell_de" type="text_de" indexed="true" stored="true" multiValued="true"/>
<copyField source="label_de" dest="spell_de"/>
<copyField source="content_de" dest="spell_de"/>
<dynamicField name="tags_de_*" type="text_de" indexed="true" stored="false" omitNorms="true"/>
<dynamicField name="ts_de_*" type="text_de" indexed="true" stored="true" multiValued="false" termVectors="true"/>
<dynamicField name="tm_de_*" type="text_de" indexed="true" stored="true" multiValued="true" termVectors="true"/>
<dynamicField name="tos_de_*" type="text_de" indexed="true" stored="true" multiValued="false" termVectors="true" omitNorms="true"/>
<dynamicField name="tom_de_*" type="text_de" indexed="true" stored="true" multiValued="true" termVectors="true" omitNorms="true"/>
-->
</fields>

View File

@@ -0,0 +1,34 @@
<types>
<!--
Example: Adding German language field types to our Solr Schema.
If you enable this, make sure you have a folder called lang containing
stopwords_de.txt and synonyms_de.txt.
For examples from other languages, see
./server/solr/configsets/sample_techproducts_configs/conf/schema.xml
from your Solr installation.
-->
<!--
<fieldType name="text_de" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.StopFilterFactory" words="lang/stopwords_de.txt" format="snowball" ignoreCase="true"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" catenateWords="1" catenateNumbers="1" catenateAll="0" protected="protwords.txt" preserveOriginal="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.GermanLightStemFilterFactory"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
<analyzer type="query">
<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.SynonymFilterFactory" synonyms="lang/synonyms_de.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory" words="lang/stopwords_de.txt" format="snowball" ignoreCase="true"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" catenateWords="0" catenateNumbers="0" catenateAll="0" protected="protwords.txt" preserveOriginal="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.GermanLightStemFilterFactory"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldType>
-->
</types>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
<!-- Spell Check
The spell check component can return a list of alternative spelling
suggestions.
http://wiki.apache.org/solr/SpellCheckComponent
-->
<searchComponent name="spellcheck" class="solr.SpellCheckComponent">
<str name="queryAnalyzerFieldType">textSpell</str>
<!-- Multiple "Spell Checkers" can be declared and used by this
component
-->
<!-- a spellchecker built from a field of the main index, and
written to disk
-->
<lst name="spellchecker">
<str name="name">default</str>
<str name="field">spell</str>
<str name="spellcheckIndexDir">spellchecker</str>
<str name="buildOnOptimize">true</str>
<!-- uncomment this to require terms to occur in 1% of the documents in order to be included in the dictionary
<float name="thresholdTokenFrequency">.01</float>
-->
</lst>
<!--
Adding German spellhecker index to our Solr index
This also requires to enable the content in schema_extra_types.xml and schema_extra_fields.xml
-->
<!--
<lst name="spellchecker">
<str name="name">spellchecker_de</str>
<str name="field">spell_de</str>
<str name="spellcheckIndexDir">./spellchecker_de</str>
<str name="buildOnOptimize">true</str>
</lst>
-->
<!-- a spellchecker that uses a different distance measure -->
<!--
<lst name="spellchecker">
<str name="name">jarowinkler</str>
<str name="field">spell</str>
<str name="distanceMeasure">
org.apache.lucene.search.spell.JaroWinklerDistance
</str>
<str name="spellcheckIndexDir">spellcheckerJaro</str>
</lst>
-->
<!-- a spellchecker that use an alternate comparator
comparatorClass be one of:
1. score (default)
2. freq (Frequency first, then score)
3. A fully qualified class name
-->
<!--
<lst name="spellchecker">
<str name="name">freq</str>
<str name="field">lowerfilt</str>
<str name="spellcheckIndexDir">spellcheckerFreq</str>
<str name="comparatorClass">freq</str>
<str name="buildOnCommit">true</str>
-->
<!-- A spellchecker that reads the list of words from a file -->
<!--
<lst name="spellchecker">
<str name="classname">solr.FileBasedSpellChecker</str>
<str name="name">file</str>
<str name="sourceLocation">spellings.txt</str>
<str name="characterEncoding">UTF-8</str>
<str name="spellcheckIndexDir">spellcheckerFile</str>
</lst>
-->
</searchComponent>

View File

@@ -0,0 +1,20 @@
# Defines Solr properties for this specific core.
solr.replication.master=false
solr.replication.slave=false
solr.replication.pollInterval=00:00:60
solr.replication.masterUrl=http://localhost:8983/solr
solr.replication.confFiles=schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml
solr.mlt.timeAllowed=2000
# You should not set your luceneMatchVersion to anything lower than your Solr
# Version.
solr.luceneMatchVersion=5.0.0
solr.pinkPony.timeAllowed=-1
# autoCommit after 10000 docs
solr.autoCommit.MaxDocs=10000
# autoCommit after 2 minutes
solr.autoCommit.MaxTime=120000
# autoSoftCommit after 2000 docs
solr.autoSoftCommit.MaxDocs=2000
# autoSoftCommit after 10 seconds
solr.autoSoftCommit.MaxTime=10000
solr.contrib.dir=../../../contrib

View File

@@ -0,0 +1,4 @@
# Contains words which shouldn't be indexed for fulltext fields, e.g., because
# they're too common. For documentation of the format, see
# http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.StopFilterFactory
# (Lines starting with a pound character # are ignored.)

View File

@@ -0,0 +1,3 @@
# Contains synonyms to use for your index. For the format used, see
# http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.SynonymFilterFactory
# (Lines starting with a pound character # are ignored.)