Ver código fonte

updated to 7.x-1.4

Bachir Soussi Chiadmi 10 anos atrás
pai
commit
d7303905a0

+ 27 - 2
CHANGELOG.txt

@@ -1,5 +1,30 @@
-Search API Solr search 1.x, dev (xx/xx/xxxx):
----------------------------------------------
+Search API Solr search 1.4 (12/25/2013):
+----------------------------------------
+- #2157839 by drunken monkey, Nick_vh: Updated config files to the newest
+  version.
+- #2130827 by drunken monkey: Added additional Solr server information to the
+  Server overview.
+- #2126281 by drunken monkey: Update error handling according to the latest
+  Search API change.
+- #2127991 by drunken monkey: Fixed handling of negated fulltext keys.
+- #2113943 by drunken monkey: Fixed clash in specifying the HTTP method for
+  searches.
+- #2127193 by jlapp: Fixed date field values returned for multi-index searches.
+- #2122155 drunken monkey: Added the "Files" tab to contextual links.
+- #1846860 by andrewbelcher, drclaw, drunken monkey, danielnolde: Added a way
+  to easily define new dynamic field types.
+- #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):
+----------------------------------------
+- #2099683 by drunken monkey: Added support for 'virtual fields' in Views.
+- #1997702 by ianthomas_uk, drunken monkey: Added "AUTO" mode for HTTP method.
+- #2033913 by drunken monkey: Fixed small error in schema.xml.
+- #2073441 by drunken monkey: Removed custom uninstall code for deleting
+  dependent servers.
+- #1882190 by corvus_ch, arnested, drunken monkey: Added optional index ID
+  prefixes.
 
 Search API Solr search 1.2 (09/01/2013):
 ----------------------------------------

+ 17 - 0
README.txt

@@ -113,6 +113,23 @@ Hidden variables
   By default, keywords that occur in more than 90% of results are ignored for
   autocomplete suggestions. This setting lets you modify that behaviour by
   providing your own ratio. Use 1 or greater to use all suggestions.
+- search_api_solr_index_prefix (default: '')
+  By default, the index ID in the Solr server is the same as the index's machine
+  name in Drupal. This setting will let you specify a prefix for the index IDs
+  on this Drupal installation. Only use alphanumeric characters and underscores.
+  Since changing the prefix makes the currently indexed data inaccessible, you
+  should change this vairable only when no indexes are currently on any Solr
+  servers.
+- search_api_solr_index_prefix_INDEX_ID (default: '')
+  Same as above, but a per-index prefix. Use the index's machine name as
+  INDEX_ID in the variable name. Per-index prefixing is done before the global
+  prefix is added, so the global prefix will come first in the final name:
+  (GLOBAL_PREFIX)(INDEX_PREFIX)(INDEX_ID)
+  The same rules as above apply for setting the prefix.
+- search_api_solr_http_get_max_length (default: 4000)
+  The maximum number of bytes that can be handled as an HTTP GET query when
+  HTTP method is AUTO. Typically Solr can handle up to 65355 bytes, but Tomcat
+  and Jetty will error at slightly less than 4096 bytes.
 
 Customizing your Solr server
 ----------------------------

+ 193 - 71
includes/service.inc

@@ -79,7 +79,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
       'excerpt' => FALSE,
       'retrieve_data' => FALSE,
       'highlight_data' => FALSE,
-      'http_method' => 'POST',
+      'http_method' => 'AUTO',
       // Default to TRUE for new servers, but to FALSE for existing ones.
       'clean_ids' => $this->options ? FALSE : TRUE,
       'autocorrect_spell' => TRUE,
@@ -197,9 +197,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
     $form['advanced']['http_method'] = array(
       '#type' => 'select',
       '#title' => t('HTTP method'),
-      '#description' => t('The HTTP method to use for sending queries. Usually, POST will work fine in all cases.'),
+      '#description' => t('The HTTP method to use for sending queries. GET will often fail with larger queries, while POST should not be cached. AUTO will use GET when possible, and POST for queries that are too large.'),
       '#default_value' => $options['http_method'],
       '#options' => array(
+        'AUTO' => t('AUTO'),
         'POST' => 'POST',
         'GET' => 'GET',
       ),
@@ -265,55 +266,157 @@ class SearchApiSolrService extends SearchApiAbstractService {
   }
 
   /**
-   * Overrides SearchApiAbstractService::supportsFeature().
+   * {@inheritdoc}
    */
   public function supportsFeature($feature) {
-    // Search API features.
-    $supported = array(
+    // First, check the features we always support.
+    $supported = drupal_map_assoc(array(
       'search_api_autocomplete',
       'search_api_facets',
       'search_api_facets_operator_or',
       'search_api_grouping',
       'search_api_mlt',
       'search_api_multi',
+      'search_api_service_extra',
       'search_api_spellcheck',
       'search_api_data_type_location',
       'search_api_data_type_geohash',
-    );
-
-    // Custom data types.
-    foreach (search_api_solr_get_dynamic_field_info() as $type => $info) {
-      $supported[] = 'search_api_data_type_' . $type;
+    ));
+    if (isset($supported[$feature])) {
+      return TRUE;
     }
 
-    $supported = drupal_map_assoc($supported);
-    return isset($supported[$feature]);
+    // If it is a custom data type, maybe we support it automatically via
+    // search_api_solr_hook_search_api_data_type_info().
+    if (substr($feature, 0, 21) != 'search_api_data_type_') {
+      return FALSE;
+    }
+    $type = substr($feature, 21);
+    $type = search_api_get_data_type_info($type);
+    // We only support it if the "prefix" key is set.
+    return $type && !empty($type['prefix']);
   }
 
   /**
    * Overrides SearchApiAbstractService::viewSettings().
+   *
+   * Returns an empty string since information is instead added via
+   * getExtraInformation().
    */
   public function viewSettings() {
-    $output = '';
-    $options = $this->options;
-
-    $output .= "<dl>\n  <dt>";
-    $output .= t('Solr server URI');
-    $output .= "</dt>\n  <dd>";
-    $output .= $this->getServerLink();
-    $output .= '</dd>';
-    if ($options['http_user']) {
-      $output .= "\n  <dt>";
-      $output .= t('Basic HTTP authentication');
-      $output .= "</dt>\n  <dd>";
-      $output .= t('Username: @user', array('@user' => $options['http_user']));
-      $output .= "</dd>\n  <dd>";
-      $output .= t('Password: @pass', array('@pass' => str_repeat('*', strlen($options['http_pass']))));
-      $output .= '</dd>';
-    }
-    $output .= "\n</dl>";
+    return '';
+  }
 
-    return $output;
+  /**
+   * {@inheritdoc}
+   */
+  public function getExtraInformation() {
+    $info = array();
+
+    $info[] = array(
+      'label' => t('Solr server URI'),
+      'info' => $this->getServerLink(),
+    );
+
+    if ($this->options['http_user']) {
+      $vars = array(
+        '@user' => $this->options['http_user'],
+        '@pass' => str_repeat('*', strlen($this->options['http_pass'])),
+      );
+      $http = t('Username: @user; Password: @pass', $vars);
+      $info[] = array(
+        'label' => t('Basic HTTP authentication'),
+        'info' => $http,
+      );
+    }
+
+    if ($this->server->enabled) {
+      // If the server is enabled, check whether Solr can be reached.
+      $ping = $this->ping();
+      if ($ping) {
+        $msg = t('The Solr server could be reached (latency: @millisecs ms).', array('@millisecs' => $ping * 1000));
+      }
+      else {
+        $msg = t('The Solr server could not be reached. Further data is therefore unavailable.');
+      }
+      $info[] = array(
+        'label' => t('Connection'),
+        'info' => $msg,
+        'status' => $ping ? 'ok' : 'error',
+      );
+
+      if ($ping) {
+        try {
+          // If Solr can be reached, provide more information. This isn't done
+          // often (only when an admin views the server details), so we clear the
+          // cache to get the current data.
+          $this->connect();
+          $this->solr->clearCache();
+          $data = $this->solr->getLuke();
+          if (isset($data->index->numDocs)) {
+            // Collect the stats
+            $stats_summary = $this->solr->getStatsSummary();
+
+            $pending_msg = $stats_summary['@pending_docs'] ? t('(@pending_docs sent but not yet processed)', $stats_summary) : '';
+            $index_msg = $stats_summary['@index_size'] ? t('(@index_size on disk)', $stats_summary) : '';
+            $indexed_message = t('@num items !pending !index_msg', array(
+              '@num' => $data->index->numDocs,
+              '!pending' => $pending_msg,
+              '!index_msg' => $index_msg,
+            ));
+            $info[] = array(
+              'label' => t('Indexed'),
+              'info' => $indexed_message,
+            );
+
+            if (!empty($stats_summary['@deletes_total'])) {
+              $info[] = array(
+                'label' => t('Pending Deletions'),
+                'info' => $stats_summary['@deletes_total'],
+              );
+            }
+
+            $info[] = array(
+              'label' => t('Delay'),
+              'info' => t('@autocommit_time before updates are processed.', $stats_summary),
+            );
+
+            $status = 'ok';
+            if (substr($stats_summary['@schema_version'], 0, 10) == 'search-api') {
+              drupal_set_message(t('Your schema.xml version is too old. Please replace all configuration files with the ones packaged with this module and re-index you data.'), 'error');
+              $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);
+              drupal_set_message($message, 'error');
+              $status = 'error';
+            }
+            $info[] = array(
+              'label' => t('Schema'),
+              'info' => $stats_summary['@schema_version'],
+              'status' => $status,
+            );
+
+            if (!empty($stats_summary['@core_name'])) {
+              $info[] = array(
+                'label' => t('Solr Core Name'),
+                'info' => $stats_summary['@core_name'],
+              );
+            }
+          }
+        }
+        catch (SearchApiException $e) {
+          $info[] = array(
+            'label' => t('Additional information'),
+            'info' => t('An error occurred while trying to retrieve additional information from the Solr server: @msg.', array('@msg' => $e->getMessage())),
+            'status' => 'error',
+          );
+        }
+      }
+    }
+
+    return $info;
   }
 
   /**
@@ -377,12 +480,12 @@ class SearchApiSolrService extends SearchApiAbstractService {
     $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();
       try {
-        $this->connect();
-        $this->solr->deleteByQuery("index_id:" . $id);
+        $this->solr->deleteByQuery("index_id:" . $this->getIndexId($id));
       }
       catch (Exception $e) {
-        watchdog_exception('search_api_solr', $e, "%type while deleting an index's data: !message in %function (line %line of %file).");
+        throw new SearchApiException($e->getMessage());
       }
     }
   }
@@ -393,7 +496,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
   public function indexItems(SearchApiIndex $index, array $items) {
     $documents = array();
     $ret = array();
-    $index_id = $index->machine_name;
+    $index_id = $this->getIndexId($index->machine_name);
     $fields = $this->getFieldNames($index);
 
     foreach ($items as $id => $item) {
@@ -481,10 +584,10 @@ class SearchApiSolrService extends SearchApiAbstractService {
         }
 
         $inner_type = search_api_extract_inner_type($type);
-        $type_info = search_api_solr_get_dynamic_field_info($inner_type);
+        $type_info = search_api_solr_get_data_type_info($inner_type);
         $pref = isset($type_info['prefix']) ? $type_info['prefix']: '';
         if (empty($type_info['always multiValued'])) {
-          $pref .= $type == $inner_type ? 's' : 'm';
+          $pref .= ($type == $inner_type) ? 's' : 'm';
         }
         if (!empty($this->options['clean_ids'])) {
           $name = $pref . '_' . str_replace(':', '$', $key);
@@ -586,33 +689,28 @@ class SearchApiSolrService extends SearchApiAbstractService {
    * called in this fashion.
    */
   public function deleteItems($ids = 'all', SearchApiIndex $index = NULL) {
-    try {
-      $this->connect();
-      if ($index) {
-        $index_id = $index->machine_name;
-        if (is_array($ids)) {
-          $solr_ids = array();
-          foreach ($ids as $id) {
-            $solr_ids[] = $this->createId($index_id, $id);
-          }
-          $this->solr->deleteByMultipleIds($solr_ids);
-        }
-        elseif ($ids == 'all') {
-          $this->solr->deleteByQuery("index_id:" . $index_id);
-        }
-        else {
-          $this->solr->deleteByQuery("index_id:" . $index_id . ' (' . $ids . ')');
+    $this->connect();
+    if ($index) {
+      $index_id = $this->getIndexId($index->machine_name);
+      if (is_array($ids)) {
+        $solr_ids = array();
+        foreach ($ids as $id) {
+          $solr_ids[] = $this->createId($index_id, $id);
         }
+        $this->solr->deleteByMultipleIds($solr_ids);
+      }
+      elseif ($ids == 'all') {
+        $this->solr->deleteByQuery("index_id:" . $index_id);
       }
       else {
-        $q = $ids == 'all' ? '*:*' : $ids;
-        $this->solr->deleteByQuery($q);
+        $this->solr->deleteByQuery("index_id:" . $index_id . ' (' . $ids . ')');
       }
-      $this->scheduleCommit();
     }
-    catch(SearchApiException $e) {
-      watchdog_exception('search_api_solr', $e, '%type while deleting items from server @server: !message in %function (line %line of %file).', array('@server' => $this->server->name));
+    else {
+      $q = $ids == 'all' ? '*:*' : $ids;
+      $this->solr->deleteByQuery($q);
     }
+    $this->scheduleCommit();
   }
 
   /**
@@ -624,6 +722,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
     $this->request_handler = NULL;
     // Get field information.
     $index = $query->getIndex();
+    $index_id = $this->getIndexId($index->machine_name);
     $fields = $this->getFieldNames($index);
     // Get Solr connection.
     $this->connect();
@@ -650,7 +749,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
     // Extract filters.
     $filter = $query->getFilter();
     $fq = $this->createFilterQueries($filter, $fields, $index->options['fields']);
-    $fq[] = 'index_id:' . $index->machine_name;
+    $fq[] = 'index_id:' . $index_id;
 
     // Extract sort.
     $sort = array();
@@ -690,7 +789,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
         }
       }
       $mlt_params['mlt.fl'] = implode(',', $mlt_fl);
-      $id = $this->createId($index->machine_name, $mlt['id']);
+      $id = $this->createId($index_id, $mlt['id']);
       $id = call_user_func(array($this->connection_class, 'phrase'), $id);
       $keys = 'id:' . $id;
     }
@@ -884,7 +983,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
       $params['fl'] = '*,score';
     }
     // Retrieve http method from server options.
-    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'POST';
+    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
 
     $call_args = array(
       'query'       => &$keys,
@@ -1020,7 +1119,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
       $result['id'] = $result['fields']['search_api_id'];
       $result['score'] = $result['fields']['search_api_relevance'];
 
-      $solr_id = $this->createId($index->machine_name, $result['id']);
+      $index_id = $this->getIndexId($index->machine_name);
+      $solr_id = $this->createId($index_id, $result['id']);
       $excerpt = $this->getExcerpt($response, $solr_id, $result['fields'], $fields);
       if ($excerpt) {
         $result['excerpt'] = $excerpt;
@@ -1248,7 +1348,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
     // #conjunction | #negation | return value
     // ----------------------------------------------------------------
     // AND          | FALSE     | A B C
-    // AND          | TRUE      | -(A B C)
+    // AND          | TRUE      | -(A AND B AND C)
     // OR           | FALSE     | ((A) OR (B) OR (C))
     // OR           | TRUE      | -A -B -C
 
@@ -1264,7 +1364,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
       }
       return '((' . implode(') OR (', $k) . '))';
     }
-    $k = implode(' ', $k);
+    $k = implode($neg ? ' AND ' : ' ', $k);
     return $neg ? "*:* AND -($k)" : $k;
   }
 
@@ -1565,7 +1665,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
 
     // Extract filters
     $fq = $this->createFilterQueries($query->getFilter(), $fields, $index->options['fields']);
-    $fq[] = 'index_id:' . $index->machine_name;
+    $fq[] = 'index_id:' . $this->getIndexId($index->machine_name);
 
     // Autocomplete magic
     $facet_fields = array();
@@ -1588,7 +1688,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
       'spellcheck.count' => 1,
     );
     // Retrieve http method from server options.
-    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'POST';
+    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
 
     $call_args = array(
       'query'       => &$keys,
@@ -1728,11 +1828,11 @@ class SearchApiSolrService extends SearchApiAbstractService {
         'type' => 'string',
       ),
     );
-    foreach ($query->getIndexes() as $index_id => $index) {
+    foreach ($query->getIndexes() as $index) {
       if (empty($index->options['fields'])) {
         continue;
       }
-      $prefix = $index_id . ':';
+      $prefix = $this->getIndexId($index->machine_name) . ':';
       foreach ($this->getFieldNames($index) as $field => $key) {
         if (!isset($solr_fields[$field])) {
           $solr_fields[$prefix . $field] = $key;
@@ -1762,7 +1862,8 @@ class SearchApiSolrService extends SearchApiAbstractService {
 
     // Restrict search to searched indexes.
     $index_filter = array();
-    foreach ($query->getIndexes() as $index_id => $index) {
+    foreach ($query->getIndexes() as $index) {
+      $index_id = $this->getIndexId($index->machine_name);
       $index_filter[] = 'index_id:' . call_user_func(array($this->connection_class, 'phrase'), $index_id);
     }
     $fq[] = implode(' OR ', $index_filter);
@@ -1814,7 +1915,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
     }
 
     // Retrieve http method from server options.
-    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'POST';
+    $http_method = !empty($this->options['http_method']) ? $this->options['http_method'] : 'AUTO';
 
     // Send search request
     $time_processing_done = microtime(TRUE);
@@ -1879,7 +1980,7 @@ class SearchApiSolrService extends SearchApiAbstractService {
             $terms = clone $terms;
             unset($terms->_empty_);
           }
-          $type = isset($index->options['fields'][$info['field']]['type']) ? search_api_extract_inner_type($index->options['fields'][$info['field']]['type']) : 'string';
+          $type = isset($fields[$info['field']]['type']) ? search_api_extract_inner_type($fields[$info['field']]['type']) : 'string';
           foreach ($terms as $term => $count) {
             if ($count >= $min_count) {
               if ($term === '_empty_') {
@@ -2041,4 +2142,25 @@ class SearchApiSolrService extends SearchApiAbstractService {
     return $this->solr->makeServletRequest($file_servlet_name, $params);
   }
 
+  /**
+   * Prefixes an index ID as configured.
+   *
+   * The resulting ID will be a concatenation of the following strings:
+   * - If set, the "search_api_solr_index_prefix" variable.
+   * - If set, the index-specific "search_api_solr_index_prefix_INDEX" variable.
+   * - The index's machine name.
+   *
+   * @param string $machine_name
+   *   The index's machine name.
+   *
+   * @return string
+   *   The prefixed machine name.
+   */
+  protected function getIndexId($machine_name) {
+    // Prepend per-index prefix.
+    $id = variable_get('search_api_solr_index_prefix_' . $machine_name, '') . $machine_name;
+    // Prepend environment prefix.
+    $id = variable_get('search_api_solr_index_prefix', '') . $id;
+    return $id;
+  }
 }

+ 35 - 31
includes/solr_connection.inc

@@ -58,10 +58,11 @@
  */
 
 /**
- * Starting point for the Solr API. Represents a Solr server resource and has
- * methods for pinging, adding, deleting, committing, optimizing and searching.
+ * Represents a Solr server resource.
+ *
+ * Contains methods for pinging, adding, deleting, committing, optimizing and
+ * searching.
  */
-
 class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
 
   /**
@@ -133,13 +134,6 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
    */
   protected $update_url;
 
-  /**
-   * The HTTP method to use for search requests.
-   *
-   * @var string
-   */
-  protected $method;
-
   /**
    * HTTP Basic Authentication header to set for requests to the Solr server.
    *
@@ -208,8 +202,6 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
    *     information to add basic HTTP authentication to all requests to the
    *     Solr server. Not set by default.
    *   - http_pass: See "http_user".
-   *   - http_method: The HTTP method to use for searches. Can be either "GET"
-   *     or "POST". Defaults to "POST".
    */
   public function __construct(array $options) {
     $options += array(
@@ -219,16 +211,12 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
       'path' => 'solr',
       'http_user' => NULL,
       'http_pass' => NULL,
-      'http_method' => 'POST',
     );
     $this->options = $options;
 
     $path = '/' . trim($options['path'], '/') . '/';
     $this->base_url = $options['scheme'] . '://' . $options['host'] . ':' . $options['port'] . $path;
 
-    // Make sure we always have a valid method set, default to POST.
-    $this->method = $options['http_method'] == 'GET' ? 'GET' : 'POST';
-
     // Set HTTP Basic Authentication parameter, if login data was set.
     if (strlen($options['http_user']) && strlen($options['http_pass'])) {
       $this->http_auth = 'Basic ' . base64_encode($options['http_user'] . ':' . $options['http_pass']);
@@ -429,7 +417,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
         }
         $response = $this->sendRawGet($url);
         $this->stats = simplexml_load_string($response->data);
-        if ($this->env_id) {
+        if ($cid) {
           cache_set($cid, $response->data, 'cache_search_api_solr');
         }
       }
@@ -813,15 +801,15 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
    *
    * Will be synchronous unless $waitSearcher is set to FALSE.
    *
-   * @param $type
+   * @param string $type
    *   Either "commit" or "optimize".
-   * @param $waitSearcher
+   * @param bool $waitSearcher
    *   (optional) Wait until a new searcher is opened and registered as the main
    *   query searcher, making the changes visible. Defaults to true.
-   * @param $timeout
+   * @param int $timeout
    *   Seconds to wait until timing out with an exception. Defaults to an hour.
    *
-   * @return
+   * @return object
    *   A response object.
    *
    * @throws SearchApiException
@@ -845,7 +833,20 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
   }
 
   /**
-   * Like PHP's built in http_build_query(), but uses rawurlencode() and no [] for repeated params.
+   * Generates an URL-encoded query string.
+   *
+   * Works like PHP's built in http_build_query() (or drupal_http_build_query())
+   * but uses rawurlencode() and no [] for repeated params, to be compatible
+   * with the Java-based servers Solr runs on.
+   *
+   *
+   * @param array $query
+   *   The query parameters which should be set.
+   * @param string $parent
+   *   Internal use only.
+   *
+   * @return string
+   *   A query string to append (after "?") to a URL.
    */
   protected function httpBuildQuery(array $query, $parent = '') {
     $params = array();
@@ -870,7 +871,7 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
   }
 
   /**
-   * Implements SearchApiSolrConnectionInterface::search().
+   * {@inheritdoc}
    */
   public function search($query = NULL, array $params = array(), $method = 'GET') {
     // Always use JSON. See
@@ -887,15 +888,18 @@ class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
     // PHP's built-in http_build_query() doesn't give us the format Solr wants.
     $queryString = $this->httpBuildQuery($params);
 
-    if ($this->method == 'GET') {
+    if ($method == 'GET' || $method == 'AUTO') {
       $searchUrl = $this->constructUrl(self::SEARCH_SERVLET, array(), $queryString);
-      return $this->sendRawGet($searchUrl);
-    }
-    else if ($this->method == 'POST') {
-      $searchUrl = $this->constructUrl(self::SEARCH_SERVLET);
-      $options['data'] = $queryString;
-      $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
-      return $this->sendRawPost($searchUrl, $options);
+      if ($method == 'GET' || strlen($searchUrl) <= variable_get('search_api_solr_http_get_max_length', 4000)) {
+        return $this->sendRawGet($searchUrl);
+      }
     }
+
+    // Method is POST, or AUTO with a long query
+    $searchUrl = $this->constructUrl(self::SEARCH_SERVLET);
+    $options['data'] = $queryString;
+    $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
+    return $this->sendRawPost($searchUrl, $options);
   }
+
 }

+ 4 - 4
includes/solr_connection.interface.inc

@@ -71,8 +71,8 @@ interface SearchApiSolrConnectionInterface {
   /**
    * Gets information about the Solr Core.
    *
-   * @return array
-   *   An array with system information.
+   * @return object
+   *   A response object with system information.
    */
   public function getSystemInfo();
 
@@ -288,8 +288,8 @@ interface SearchApiSolrConnectionInterface {
    *   documentation). Use arrays for parameter keys used more than once (e.g.,
    *   facet.field).
    * @param string $method
-   *   The HTTP method to use. Must be either "GET" or "POST". Defaults to
-   *   "GET".
+   *   The HTTP method to use. Must be either "GET", "POST" or "AUTO". Defaults
+   *   to "GET".
    *
    * @return object
    *   A response object.

+ 34 - 29
search_api_solr.api.php

@@ -101,45 +101,50 @@ function hook_search_api_solr_multi_query_alter(array &$call_args, SearchApiMult
 }
 
 /**
- * Define how Search API Solr should index different data types.
+ * Provide Solr dynamic fields as Search API data types.
  *
- * It is important to make sure that any types you define are also declared to
- * Search API using hook_search_api_data_type_info().
+ * This serves as a placeholder for documenting additional keys for
+ * hook_search_api_data_type_info() which are recognized by this module to
+ * automatically support dynamic field types from the schema.
  *
  * @return array
- *   An array containing data type definitions, keyed by their type identifier
- *   and containing the following keys:
- *   - prefix: The prefix used by the dynamic field type.
- *   - always multiValued: (optional) Whether the single/multiple prefix should
- *     be skipped for this data type. Defaults to FALSE.
+ *   In addition to the keys for the individual types that are defined by
+ *   hook_search_api_data_type_info(), the following keys are regonized:
+ *   - prefix: The Solr field name prefix to use for this type. Should match
+ *     two existing dynamic fields definitions with names "{PREFIX}s_*" and
+ *     "{PREFIX}m_*".
+ *   - always multiValued: (optional) If TRUE, only the dynamic field name
+ *     prefix (without the "_*" portion) with multiValued="true" should be given
+ *     by "prefix", instead of the common prefix part for both the single-valued
+ *     and the multi-valued field. This should be the case for all fulltext
+ *     fields, since they might already be tokenized by the Search API. Defaults
+ *     to FALSE.
  *
- * @see hook_search_api_solr_dynamic_field_info_alter()
- * @see search_api_solr_get_dynamic_field_info()
- * @see hook_search_api_data_type_info().
+ *@see hook_search_api_data_type_info()
  */
-function hook_search_api_solr_dynamic_field_info() {
+function search_api_solr_hook_search_api_data_type_info() {
   return array(
-    'example_type' => array(
-      'prefix' => 'ex',
-      // Could be omitted, as FALSE is the default.
-      'always multiValued' => FALSE,
+    // You can use any identifier you want here, but it makes sense to use the
+    // field type name from schema.xml.
+    'edge_n2_kw_text' => array(
+      // Stock hook_search_api_data_type_info() info:
+      'name' => t('Fulltext (w/ partial matching)'),
+      'fallback' => 'text',
+      // Dynamic field with name="te_*".
+      'prefix' => 'te',
+      // Fulltext types should always be multi-valued.
+      'always multiValued' => TRUE,
+    ),
+    'tlong' => array(
+      // Stock hook_search_api_data_type_info() info:
+      'name' => t('TrieLong'),
+      'fallback' => 'integer',
+      // Dynamic fields with name="its_*" and name="itm_*".
+      'prefix' => 'it',
     ),
   );
 }
 
-/**
- * Alter the data type indexing info.
- *
- * @param array $infos
- *   The item type info array, keyed by type identifier.
- *
- * @see hook_search_api_solr_dynamic_field_info()
- */
-function hook_search_api_solr_dynamic_field_info_alter(array &$infos) {
-  // Change the prefix used for example_type.
-  $info['example_type']['prefix'] = 'ex2';
-}
-
 /**
  * @} End of "addtogroup hooks".
  */

+ 3 - 3
search_api_solr.info

@@ -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 2013-09-01
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2013-12-25
+version = "7.x-1.4"
 core = "7.x"
 project = "search_api_solr"
-datestamp = "1378026413"
+datestamp = "1387970905"
 

+ 2 - 5
search_api_solr.install

@@ -59,13 +59,10 @@ function search_api_solr_requirements($phase) {
  * Implements hook_uninstall().
  */
 function search_api_solr_uninstall() {
-  if (module_exists('search_api')) {
-    db_delete('search_api_server')
-      ->condition('class', 'search_api_solr_service')
-      ->execute();
-  }
   variable_del('search_api_solr_last_optimize');
   variable_del('search_api_solr_autocomplete_max_occurrences');
+  variable_del('search_api_solr_index_prefix');
+  variable_del('search_api_solr_http_get_max_length');
 }
 
 /**

+ 112 - 87
search_api_solr.module

@@ -14,11 +14,12 @@ function search_api_solr_menu() {
     'description' => 'View Solr configuration files.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('search_api_solr_solr_config_form', 5),
-    'access callback' => 'search_api_access_server_files',
+    'access callback' => 'search_api_solr_access_server_files',
     'access arguments' => array(5),
     'file' => 'search_api_solr.admin.inc',
     'type' => MENU_LOCAL_TASK,
     'weight' => -1,
+    'context' => MENU_CONTEXT_INLINE | MENU_CONTEXT_PAGE,
   );
 
   return $items;
@@ -28,15 +29,18 @@ function search_api_solr_menu() {
  * Implements hook_search_api_service_info().
  */
 function search_api_solr_search_api_service_info() {
+  $variables = array(
+    '@solr_wiki_url' => url('http://wiki.apache.org/solr/SolrQuerySyntax'),
+    '@readme_url' => url(drupal_get_path('module', 'search_api_solr') . '/README.txt'),
+  );
   $services['search_api_solr_service'] = array(
     'name' => t('Solr service'),
-    'description' => t('<p>Index items using an Apache Solr search server.</p>' .
-        '<ul>' . '<li>All field types are supported and indexed in a special way, with URI/String and Integer/Duration being equivalent.</li>' .
-        '<li>See <a href="@url">the Solr wiki</a> for information about the "direct" parse mode.</li>' .
-        '<li>Supports the search_api_facets and search_api_multi features.</li>' .
-        '<li>Will use internal Solr preprocessors, so Search API preprocessors should for the most part be deactivated.</li>' .
-        '<li>See the README.txt file provided with this module for details.</li>' . '</ul>',
-        array('@url' => url('http://wiki.apache.org/solr/SolrQuerySyntax'))),
+    'description' => t('<p>Index items using an Apache Solr search server.</p>
+<ul>
+  <li>See <a href="@solr_wiki_url">the Solr wiki</a> for information about the "direct" parse mode.</li>
+  <li>Will use internal Solr preprocessors, so Search API preprocessors should for the most part be deactivated.</li>
+  <li>See the <a href="@readme_url">README.txt</a> file provided with this module for details.</li>
+</ul>', $variables),
     'class' => 'SearchApiSolrService',
   );
   return $services;
@@ -58,20 +62,6 @@ function search_api_solr_help($path, array $arg = array()) {
       }
     }
   }
-  elseif ($path == 'admin/config/search/search_api/server/%' && !empty($arg[5])) {
-    $server = search_api_server_load($arg[5]);
-    if ($server && $server->enabled && $server->class == 'search_api_solr_service') {
-      $ping = $server->ping();
-      $type = $ping ? 'status' : 'error';
-      if ($ping) {
-        $msg = t('The Solr server could be reached (latency: @millisecs ms).', array('@millisecs' => $ping * 1000));
-      }
-      else {
-        $msg = t('The Solr server could not be reached.');
-      }
-      drupal_set_message($msg, $type);
-    }
-  }
 }
 
 /**
@@ -113,83 +103,109 @@ function search_api_solr_search_api_server_update(SearchApiServer $server) {
 }
 
 /**
- * Returns either all dynamic field types, or a specific one.
+ * Implements hook_views_api().
+ */
+function search_api_solr_views_api() {
+  if (module_exists('search_api_views')) {
+    return array(
+      'api' => 3,
+    );
+  }
+}
+
+/**
+ * Retrieves Solr-specific data for available data types.
  *
- * @param $type
- *   If specified, the type whose definition should be returned.
+ * Returns the data type information for both the default Search API data types
+ * and custom data types defined by hook_search_api_data_type_info(). Names for
+ * default data types are not included, since they are not relevant to the Solr
+ * service class.
  *
- * @return array
- *   If $type was not given, an array containing all custom dynamic fields, in
- *   the format specified by hook_search_api_solr_dynamic_field_info().
- *   Otherwise, the definition for the given type, or NULL if it is unknown.
+ * We're adding some extra Solr field information for the default search api
+ * data types (as well as on behalf of a couple contrib field types). The
+ * extra information we're adding is documented in
+ * search_api_solr_hook_search_api_data_type_info(). You can use the same
+ * additional keys in hook_search_api_data_type_info() to support custom
+ * dynamic fields in your indexes with Solr.
+ *
+ * @param string|null $type
+ *   (optional) A specific type for which the information should be returned.
+ *   Defaults to returning all information.
  *
- * @see hook_search_api_solr_dynamic_field_info().
+ * @return array|null
+ *   If $type was given, information about that type or NULL if it is unknown.
+ *   Otherwise, an array of all types. The format in both cases is the same as
+ *   for search_api_get_data_type_info().
+ *
+ * @see search_api_get_data_type_info()
+ * @see search_api_solr_hook_search_api_data_type_info()
  */
-function search_api_solr_get_dynamic_field_info($type = NULL) {
+function search_api_solr_get_data_type_info($type = NULL) {
   $types = &drupal_static(__FUNCTION__);
+
   if (!isset($types)) {
-    $types = module_invoke_all('search_api_solr_dynamic_field_info');
-    $types = $types ? $types : array();
-    drupal_alter('search_api_solr_dynamic_field_info', $types);
+    // Grab the stock search_api data types.
+    $types = search_api_get_data_type_info();
+
+    // Add our extras for the default search api fields.
+    $types += array(
+      'text' => array(
+        'prefix' => 'tm',
+        'always multiValued' => TRUE,
+      ),
+      'string' => array(
+        'prefix' => 's',
+      ),
+      'integer' => array(
+        'prefix' => 'i',
+      ),
+      'decimal' => array(
+        'prefix' => 'f',
+      ),
+      'date' => array(
+        'prefix' => 'd',
+      ),
+      'duration' => array(
+        'prefix' => 'i',
+      ),
+      'boolean' => array(
+        'prefix' => 'b',
+      ),
+      'uri' => array(
+        'prefix' => 's',
+      ),
+      'tokens' => array(
+        'prefix' => 'tm',
+        'always multiValued' => TRUE,
+      ),
+    );
+
+    // Extra data type info.
+    $extra_types_info = array(
+      'location' => array(
+        'prefix' => 'loc',
+      ),
+      'geohash' => array(
+        'prefix' => 'geo',
+      ),
+    );
+
+    // For the extra types, only add our extra info if it's already been defined.
+    foreach ($extra_types_info as $key => $info) {
+      if (array_key_exists($key, $types)) {
+        // Merge our extras into the data type info
+        $types[$key] += $info;
+      }
+    }
   }
+
+  // Return the info.
   if (isset($type)) {
     return isset($types[$type]) ? $types[$type] : NULL;
   }
   return $types;
 }
 
-/**
- * Implements hook_search_api_solr_dynamic_field_info().
- */
-function search_api_solr_search_api_solr_dynamic_field_info() {
-  return array(
-    'text' => array(
-      'prefix' => 'tm',
-      'always multiValued' => TRUE,
-    ),
-    'tokens' => array(
-      'prefix' => 'tm',
-      'always multiValued' => TRUE,
-    ),
-    'string' => array(
-      'prefix' => 's',
-      'always multiValued' => FALSE,
-    ),
-    'integer' => array(
-      'prefix' => 'i',
-      'always multiValued' => FALSE,
-    ),
-    'decimal' => array(
-      'prefix' => 'f',
-      'always multiValued' => FALSE,
-    ),
-    'date' => array(
-      'prefix' => 'd',
-      'always multiValued' => FALSE,
-    ),
-    'duration' => array(
-      'prefix' => 'i',
-      'always multiValued' => FALSE,
-    ),
-    'boolean' => array(
-      'prefix' => 'b',
-      'always multiValued' => FALSE,
-    ),
-    'uri' => array(
-      'prefix' => 's',
-      'always multiValued' => FALSE,
-    ),
-    'location' => array(
-      'prefix' => 'loc',
-      'always multiValued' => FALSE,
-    ),
-    'geohash' => array(
-      'prefix' => 'geohash',
-      'always multiValued' => FALSE,
-    ),
-  );
-}
-
 /**
  * Retrieves a list of all config files of a server.
  *
@@ -229,6 +245,15 @@ function search_api_solr_server_get_files(SearchApiServer $server, $dir_name = N
   return array_reduce($result, 'array_merge', array());
 }
 
+/**
+ * @deprecated
+ *
+ * @see search_api_solr_access_server_files()
+ */
+function search_api_access_server_files(SearchApiServer $server) {
+  return search_api_solr_access_server_files($server);
+}
+
 /**
  * Access callback for a server's "Files" tab.
  *
@@ -241,7 +266,7 @@ function search_api_solr_server_get_files(SearchApiServer $server, $dir_name = N
  * @return bool
  *   TRUE if access should be granted, FALSE otherwise.
  */
-function search_api_access_server_files(SearchApiServer $server) {
+function search_api_solr_access_server_files(SearchApiServer $server) {
   if (!user_access('administer search_api')) {
     return FALSE;
   }

+ 62 - 0
search_api_solr.views.inc

@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Views integration code for the Search API Solr module.
+ */
+
+/**
+ * Implements hook_views_data_alter().
+ *
+ * Adds field handlers for "virtual" fields, if the index's Solr server has
+ * "Retrieve results data from Solr" enabled.
+ */
+function search_api_solr_views_data_alter(array &$data) {
+  try {
+    foreach (search_api_index_load_multiple(FALSE) as $index) {
+      $server = $index->server();
+      if (!$server || empty($server->options['retrieve_data'])) {
+        return;
+      }
+      // Fill in base data.
+      $key = 'search_api_index_' . $index->machine_name;
+      $table = & $data[$key];
+
+      try {
+        $wrapper = $index->entityWrapper(NULL, FALSE);
+      }
+      catch (EntityMetadataWrapperException $e) {
+        watchdog_exception('search_api_solr', $e, "%type while retrieving metadata for index %index: !message in %function (line %line of %file).", array('%index' => $index->name), WATCHDOG_WARNING);
+        continue;
+      }
+
+      // Remember fields that aren't added by data alterations, etc. (since
+      // there isn't any other way to tell them apart).
+      $normal_fields = array();
+      foreach ($wrapper as $key => $property) {
+        $normal_fields[$key] = TRUE;
+      }
+
+      try {
+        $wrapper = $index->entityWrapper(NULL);
+      }
+      catch (EntityMetadataWrapperException $e) {
+        watchdog_exception('search_api_solr', $e, "%type while retrieving metadata for index %index: !message in %function (line %line of %file).", array('%index' => $index->name), WATCHDOG_WARNING);
+        continue;
+      }
+
+      // Add field handlers for items added by data alterations, etc.
+      foreach ($wrapper as $key => $property) {
+        if (empty($normal_fields[$key])) {
+          $info = $property->info();
+          if ($info) {
+            entity_views_field_definition($key, $info, $table);
+          }
+        }
+      }
+    }
+  }
+  catch (Exception $e) {
+    watchdog_exception('search_api_views', $e);
+  }
+}

+ 2 - 2
solr-conf/1.4/schema.xml

@@ -70,8 +70,8 @@
       so that range queries work correctly.
     -->
     <fieldType name="sint" class="solr.TrieIntField" sortMissingLast="true" omitNorms="true"/>
-    <fieldType name="slong" class="solr.TrieFloatField" sortMissingLast="true" omitNorms="true"/>
-    <fieldType name="sfloat" class="solr.TrieLongField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="sfloat" class="solr.TrieFloatField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="slong" class="solr.TrieLongField" sortMissingLast="true" omitNorms="true"/>
     <fieldType name="sdouble" class="solr.TrieDoubleField" sortMissingLast="true" omitNorms="true"/>
 
     <!--

+ 5 - 5
solr-conf/3.x/schema.xml

@@ -10,7 +10,7 @@
  http://wiki.apache.org/solr/SchemaXml
 -->
 
-<schema name="drupal-4.1-solr-3.x" version="1.3">
+<schema name="drupal-4.2-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
@@ -71,8 +71,8 @@
       so that range queries work correctly.
     -->
     <fieldType name="sint" class="solr.TrieIntField" sortMissingLast="true" omitNorms="true"/>
-    <fieldType name="slong" class="solr.TrieFloatField" sortMissingLast="true" omitNorms="true"/>
-    <fieldType name="sfloat" class="solr.TrieLongField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="sfloat" class="solr.TrieFloatField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="slong" class="solr.TrieLongField" sortMissingLast="true" omitNorms="true"/>
     <fieldType name="sdouble" class="solr.TrieDoubleField" sortMissingLast="true" omitNorms="true"/>
 
     <!--
@@ -181,7 +181,7 @@
                 catenateWords="1"
                 catenateNumbers="1"
                 catenateAll="0"
-                splitOnCaseChange="1"
+                splitOnCaseChange="0"
                 preserveOriginal="1"/>
         <filter class="solr.LengthFilterFactory" min="2" max="100" />
         <filter class="solr.LowerCaseFilterFactory"/>
@@ -204,7 +204,7 @@
                 catenateWords="0"
                 catenateNumbers="0"
                 catenateAll="0"
-                splitOnCaseChange="1"
+                splitOnCaseChange="0"
                 preserveOriginal="1"/>
         <filter class="solr.LengthFilterFactory" min="2" max="100" />
         <filter class="solr.LowerCaseFilterFactory"/>

+ 19 - 17
solr-conf/3.x/solrconfig.xml

@@ -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.1-solr-3.x">
+<config name="drupal-4.2-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)
@@ -68,8 +68,9 @@
        the classpath, this is useful for including all jars in a
        directory.
     -->
-  <lib dir="../../contrib/extraction/lib" />
-  <lib dir="../../contrib/clustering/lib/" />
+  <lib dir="${solr.contrib.dir:../../contrib}/extraction/lib" />
+  <lib dir="${solr.contrib.dir:../../contrib}/clustering/lib/" />
+
   <!-- The velocity library has been known to crash Solr in some
        instances when deployed as a war file to Tomcat. Therefore all
        references have been removed from the default configuration.
@@ -1076,7 +1077,7 @@
   <!-- Solr Replication
 
        The SolrReplicationHandler supports replicating indexes from a
-       "master" used for indexing and "salves" used for queries.
+       "master" used for indexing and "slaves" used for queries.
 
        http://wiki.apache.org/solr/SolrReplication
 
@@ -1084,19 +1085,19 @@
        this is just a slave and remove  the <lst name="slave"> section
        if this is just a master.
     -->
-     <requestHandler name="/replication" class="solr.ReplicationHandler" >
-       <lst name="master">
-         <str name="enable">${solr.replication.master:false}</str>
-         <str name="replicateAfter">commit</str>
-         <str name="replicateAfter">startup</str>
-         <str name="confFiles">${solr.replication.confFiles:schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml}</str>
-       </lst>
-       <lst name="slave">
-         <str name="enable">${solr.replication.slave:false}</str>
-         <str name="masterUrl">${solr.replication.masterUrl:http://localhost:8983/solr}/replication</str>
-         <str name="pollInterval">${solr.replication.pollInterval:00:00:60}</str>
-       </lst>
-     </requestHandler>
+  <requestHandler name="/replication" class="solr.ReplicationHandler" >
+    <lst name="master">
+      <str name="enable">${solr.replication.master:false}</str>
+      <str name="replicateAfter">commit</str>
+      <str name="replicateAfter">startup</str>
+      <str name="confFiles">${solr.replication.confFiles:schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml}</str>
+    </lst>
+    <lst name="slave">
+      <str name="enable">${solr.replication.slave:false}</str>
+      <str name="masterUrl">${solr.replication.masterUrl:http://localhost:8983/solr}/replication</str>
+      <str name="pollInterval">${solr.replication.pollInterval:00:00:60}</str>
+    </lst>
+  </requestHandler>
 
   <!-- Search Components
 
@@ -1595,6 +1596,7 @@
           http://wiki.apache.org/solr/SpellCheckComponent
        -->
       <searchComponent name="spellcheck" class="solr.SpellCheckComponent">
+
         <str name="queryAnalyzerFieldType">textSpell</str>
 
         <!-- a spellchecker built from a field of the main index -->

+ 5 - 1
solr-conf/3.x/solrcore.properties

@@ -5,8 +5,12 @@ 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 luceneVersion to anything lower then your Solr Version.
+# You should not set your luceneMatchVersion to anything lower than your Solr
+# Version.
 solr.luceneMatchVersion=LUCENE_35
 solr.pinkPony.timeAllowed=-1
+# autoCommit after 10000 docs
 solr.autoCommit.MaxDocs=10000
+# autoCommit after 2 minutes
 solr.autoCommit.MaxTime=120000
+solr.contrib.dir=../../contrib

+ 1 - 1
solr-conf/3.x/stopwords.txt

@@ -1,4 +1,4 @@
 # Contains words which shouldn't be indexed for fulltext fields, e.g., because
-# they're to common. For documentation of the format, see
+# 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.)

+ 10 - 5
solr-conf/4.x/schema.xml

@@ -10,7 +10,7 @@
  http://wiki.apache.org/solr/SchemaXml
 -->
 
-<schema name="drupal-4.1-solr-4.x" version="1.3">
+<schema name="drupal-4.2-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
@@ -71,8 +71,8 @@
       so that range queries work correctly.
     -->
     <fieldType name="sint" class="solr.TrieIntField" sortMissingLast="true" omitNorms="true"/>
-    <fieldType name="slong" class="solr.TrieFloatField" sortMissingLast="true" omitNorms="true"/>
-    <fieldType name="sfloat" class="solr.TrieLongField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="sfloat" class="solr.TrieFloatField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="slong" class="solr.TrieLongField" sortMissingLast="true" omitNorms="true"/>
     <fieldType name="sdouble" class="solr.TrieDoubleField" sortMissingLast="true" omitNorms="true"/>
 
     <!--
@@ -181,7 +181,7 @@
                 catenateWords="1"
                 catenateNumbers="1"
                 catenateAll="0"
-                splitOnCaseChange="1"
+                splitOnCaseChange="0"
                 preserveOriginal="1"/>
         <filter class="solr.LengthFilterFactory" min="2" max="100" />
         <filter class="solr.LowerCaseFilterFactory"/>
@@ -204,7 +204,7 @@
                 catenateWords="0"
                 catenateNumbers="0"
                 catenateAll="0"
-                splitOnCaseChange="1"
+                splitOnCaseChange="0"
                 preserveOriginal="1"/>
         <filter class="solr.LengthFilterFactory" min="2" max="100" />
         <filter class="solr.LowerCaseFilterFactory"/>
@@ -363,6 +363,11 @@
     -->
     <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" />

+ 53 - 23
solr-conf/4.x/solrconfig.xml

@@ -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.1-solr-4.x" >
+<config name="drupal-4.2-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)
@@ -68,8 +68,9 @@
        the classpath, this is useful for including all jars in a
        directory.
     -->
-  <lib dir="../../contrib/extraction/lib" />
-  <lib dir="../../contrib/clustering/lib/" />
+  <lib dir="${solr.contrib.dir:../../../contrib}/extraction/lib" />
+  <lib dir="${solr.contrib.dir:../../../contrib}/clustering/lib/" />
+
   <!-- The velocity library has been known to crash Solr in some
        instances when deployed as a war file to Tomcat. Therefore all
        references have been removed from the default configuration.
@@ -204,10 +205,6 @@
       -->
     <!-- <termIndexInterval>256</termIndexInterval> -->
 
-    <useCompoundFile>false</useCompoundFile>
-    <ramBufferSizeMB>32</ramBufferSizeMB>
-    <mergeFactor>10</mergeFactor>
-
     <!-- Unlock On Startup
 
          If true, unlock any held write or commit locks on startup.
@@ -306,6 +303,16 @@
       <maxTime>${solr.autoCommit.MaxTime:120000}</maxTime>
     </autoCommit>
 
+    <!-- softAutoCommit is like autoCommit except it causes a
+         'soft' commit which only ensures that changes are visible
+         but does not ensure that data is synced to disk.  This is
+         faster and more near-realtime friendly than a hard commit.
+    -->
+    <autoSoftCommit>
+      <maxDocs>${solr.autoSoftCommit.MaxDocs:2000}</maxDocs>
+      <maxTime>${solr.autoSoftCommit.MaxTime:10000}</maxTime>
+    </autoSoftCommit>
+
     <!-- Update Related Event Listeners
 
          Various IndexWriter related events can trigger Listeners to
@@ -337,6 +344,17 @@
          <arr name="env"> <str>MYVAR=val1</str> </arr>
        </listener>
       -->
+    <!-- Enables a transaction log, currently used for real-time get.
+         "dir" - the target directory for transaction logs, defaults to the
+         solr data directory.  -->
+    <updateLog>
+      <str name="dir">${solr.data.dir:}</str>
+      <!-- if you want to take control of the synchronization you may specify
+           the syncLevel as one of the following where ''flush'' is the default.
+           Fsync will reduce throughput.
+           <str name="syncLevel">flush|fsync|none</str>
+      -->
+    </updateLog>
   </updateHandler>
 
   <!-- IndexReaderFactory
@@ -1022,8 +1040,7 @@
        Admin Handlers - This will register all the standard admin
        RequestHandlers.
     -->
-  <requestHandler name="/admin/"
-                  class="solr.admin.AdminHandlers" />
+  <requestHandler name="/admin/" class="solr.admin.AdminHandlers" />
   <!-- This single handler is equivalent to the following... -->
   <!--
      <requestHandler name="/admin/luke"       class="solr.admin.LukeRequestHandler" />
@@ -1068,7 +1085,7 @@
   <!-- Solr Replication
 
        The SolrReplicationHandler supports replicating indexes from a
-       "master" used for indexing and "salves" used for queries.
+       "master" used for indexing and "slaves" used for queries.
 
        http://wiki.apache.org/solr/SolrReplication
 
@@ -1076,19 +1093,31 @@
        this is just a slave and remove  the <lst name="slave"> section
        if this is just a master.
     -->
-     <requestHandler name="/replication" class="solr.ReplicationHandler" >
-       <lst name="master">
-         <str name="enable">${solr.replication.master:false}</str>
-         <str name="replicateAfter">commit</str>
-         <str name="replicateAfter">startup</str>
-         <str name="confFiles">${solr.replication.confFiles:schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml}</str>
-       </lst>
-       <lst name="slave">
-         <str name="enable">${solr.replication.slave:false}</str>
-         <str name="masterUrl">${solr.replication.masterUrl:http://localhost:8983/solr}/replication</str>
-         <str name="pollInterval">${solr.replication.pollInterval:00:00:60}</str>
-       </lst>
-     </requestHandler>
+  <requestHandler name="/replication" class="solr.ReplicationHandler" >
+    <lst name="master">
+      <str name="enable">${solr.replication.master:false}</str>
+      <str name="replicateAfter">commit</str>
+      <str name="replicateAfter">startup</str>
+      <str name="confFiles">${solr.replication.confFiles:schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml}</str>
+    </lst>
+    <lst name="slave">
+      <str name="enable">${solr.replication.slave:false}</str>
+      <str name="masterUrl">${solr.replication.masterUrl:http://localhost:8983/solr}/replication</str>
+      <str name="pollInterval">${solr.replication.pollInterval:00:00:60}</str>
+    </lst>
+  </requestHandler>
+
+  <!-- Realtime get handler, guaranteed to return the latest stored fields of
+       any document, without the need to commit or open a new searcher.  The
+       current implementation relies on the updateLog feature being enabled.
+  -->
+  <requestHandler name="/get" class="solr.RealTimeGetHandler">
+    <lst name="defaults">
+      <str name="omitHeader">true</str>
+      <str name="wt">json</str>
+      <str name="indent">true</str>
+    </lst>
+  </requestHandler>
 
   <!-- Search Components
 
@@ -1587,6 +1616,7 @@
           http://wiki.apache.org/solr/SpellCheckComponent
        -->
       <searchComponent name="spellcheck" class="solr.SpellCheckComponent">
+
         <str name="queryAnalyzerFieldType">textSpell</str>
 
         <!-- a spellchecker built from a field of the main index -->

+ 9 - 1
solr-conf/4.x/solrcore.properties

@@ -5,8 +5,16 @@ 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 luceneVersion to anything lower then your Solr Version.
+# You should not set your luceneMatchVersion to anything lower than your Solr
+# Version.
 solr.luceneMatchVersion=LUCENE_40
 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