I have to use 4 indexes only 1 of which is Drupal format. This mostly works pretty well using search_api_solr, except for a couple of small 'hacks' I have to do.

Of course I can keep patching future releases locally but wondered if these 'hacks' might be useful to anyone else. They don't seem to have any impact on my Drupal index queries and go a long way to making the search_api_solr module very useful for my non-Drupal indexes. It would be nice to be able to upgrade without patching. :)

Thank you for all your work on these modules! We have quite an eminent site coming up to launch in November and this multi-index Solr search is one of the major features!

First hack: One of my indexes has no 'id' field, it has 'identifier'. This means that the solr connection class's ping method fails. (I don't ever call ping btw, I believe it is used in the Service class).

Index: service.inc
===================================================================
--- service.inc	(revision 499)
+++ service.inc	(working copy)
@@ -94,6 +94,13 @@
       '#description' => t('The path that identifies the Solr instance to use on the server.'),
       '#default_value' => $options['path'],
     );
+    // field used in the ping query
+    $form['default_field'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Solr default field'),
+      '#description' => t('The field required by any query to this server.'),
+      '#default_value' => $options['default_field'],
+    );
 
     $form['http'] = array(
       '#type' => 'fieldset',

Index: solr_connection.inc
===================================================================
--- solr_connection.inc	(revision 500)
+++ solr_connection.inc	(working copy)
@@ -40,13 +42,16 @@
       'path' => '',
       'http_user' => NULL,
       'http_pass' => NULL,
+      'default_field'=>'id',
     );
     parent::__construct($options['host'], $options['port'], $options['path']);
     if ($options['http_user'] && $options['http_pass']) {
       $this->http_auth = 'Basic ' . base64_encode($options['http_user'] . ':' . $options['http_pass']);
     }
     // Since /ping otherwise complains about missing default field.
-    $this->_pingUrl .= '?q=id:1';
+    // $this->_pingUrl.= '?q=id:1';
+    // not all servers have field 'id'
+    $this->_pingUrl .= '?q='.$options['default_field'].':1';
   }

Second 'hack' is due to my non-Drupal indexes not having the fieldname prefixes that denote type etc., e.g.

"ss_search_api_language" and it's corresponding facet field "f_ss_search_api_language"

instead I have "subjectText" and "subjectString", which means that this code ...

// String fields have their own corresponding facet fields.
if ($field[0] == 's') {
  $field = 'f_' . $field;
}

... causes my facet query to ask for f_subjectString which returns an Exception message.

The following patch deals with this problem and results in all of my facet queries, both Drupal and non-Drupal, executing without error and returning their facets.

Index: service.inc
===================================================================
--- service.inc	(revision 1570)
+++ service.inc	(working copy)
@@ -756,7 +756,7 @@
 
       foreach ($extract_facets as $delta => $info) {
         $field = $fields[$info['field']];
-        if ($field[0] == 's') {
+        if (preg_match('/^s[a-z]_/i', $field)) {
           $field = 'f_' . $field;
         }
         if (!empty($facet_fields->$field)) {
@@ -986,7 +986,7 @@
       }
       $field = $f = $fields[$info['field']];
       // String fields have their own corresponding facet fields.
-      if ($field[0] == 's') {
+      if (preg_match('/^s[a-z]_/i', $field)) {
         $field = 'f_' . $field;
       }
       // Check for the "or" operator.
@@ -1459,7 +1459,7 @@
         $facet_fields = $response->facet_counts->facet_fields;
         foreach ($facets as $delta => $info) {
           $field = $solr_fields[$info['field']];
-          if ($field[0] == 's') {
+          if (preg_match('/^s[a-z]_/i', $field)) {
             $field = 'f_' . $field;
           }
           if (!empty($facet_fields->$field)) {

If there are better suggestions I'll be happy to hear them, however we are close to launch so am going to be quite careful about too much late refactoring. :)

Comments

drunken monkey’s picture

Instead of hacking the module, you could just write a small custom module extending the service class and substituting that for this module's service class (or adding it as another option). This is the preferred variant and should eliminate your update problems.

Regarding your patches:
Adding a complete new option that only few users will ever need, or even understand if they don't know too much about Solr and this module's code, seems a bit overkill to fix this. You might run into problems with a custom class there, however, as I think you'd have to override the connection class as well. If you provide a small patch, adding a way to override this from the service class (e.g., adding a setter for the default field), I'd gladly commit it.

The second one doesn't really solve the problem, but just makes it more unlikely to occur, additionally carrying a bit of a performance loss (probably rather minor, but still). Refactoring this code to use a new helper method in all three places (getFacetField() or something like that), so this can be overridden more easily, seems the better solution. I'd also gladly commit a patch for that.

In general, I'm very open to improving the extendability of the service class / module to serve use cases such as yours. I just don't want to hamper the „normal“ use case by doing so.

zenlan’s picture

StatusFileSize
new3.52 KB

Ok, patch attached. I hope I have understood correctly. Both changes are in the same patch file, I hope that is ok.

drunken monkey’s picture

Title: My patch for a non-Drupal index » Add flexibility for facet fields
Status: Active » Needs review
StatusFileSize
new3.48 KB

Yes, thanks, that already looks quite good.
Just a few changes on my part:
- The new method(s) should be documented.
- Shortened getFacetField() since I feel it's simple enough for that.
- Removed the preConnect() addition – connect() is well suited for being overridden directly where you could the same. Either copy the code from connect(), or use parent::connect() in your overridden method.

Please see if the attached patch still works for you, and I'll commit it.

zenlan’s picture

Yep, that works fine for me. Thanks. :)

drunken monkey’s picture

Status: Needs review » Fixed

OK, committed.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.