? contrib/.svn
? contrib/apachesolr_attachments/.svn
? contrib/apachesolr_image/.svn
? contrib/apachesolr_lang/.svn
? contrib/apachesolr_mlt/.svn
? contrib/apachesolr_multisitesearch/.svn
? contrib/apachesolr_nodeaccess/.svn
? contrib/apachesolr_nodeaccess/tests/.svn
Index: apachesolr.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.module,v
retrieving revision 1.1.2.12.2.69
diff -u -p -r1.1.2.12.2.69 apachesolr.module
--- apachesolr.module	6 Dec 2008 01:23:50 -0000	1.1.2.12.2.69
+++ apachesolr.module	8 Dec 2008 21:12:23 -0000
@@ -452,23 +452,23 @@ function apachesolr_node_to_document($ni
     $node->body = drupal_render($node->content);
     $node->title = apachesolr_clean_text($node->title);
 
-    $text = check_plain($node->title) . ' ' . $node->body;
+    $text = $node->body;
 
-    // Fetch extra data normally not visible
+    // Fetch extra data normally not visible, including comments.
     $extra = node_invoke_nodeapi($node, 'update index');
-    $text .= implode(' ', $extra);
+    $text .= "\n\n" . implode(' ', $extra);
+    $text = apachesolr_strip_ctl_chars($text);
 
     $document = new Apache_Solr_Document();
     $document->id = apachesolr_document_id($node->nid);
     $document->site = url(NULL, array('absolute' => TRUE));
     $document->hash = apachesolr_site_hash();
     $document->url = url('node/' . $node->nid, array('absolute' => TRUE));
-
     $document->nid = $node->nid;
     $document->status = $node->status;
     $document->uid = $node->uid;
     $document->title = $node->title;
-    $document->body  = apachesolr_clean_text($node->body);
+    $document->body = strip_tags($text);
     $document->type  = $node->type;
     $document->changed = $node->changed;
     $document->comment_count = $node->comment_count;
@@ -485,7 +485,6 @@ function apachesolr_node_to_document($ni
       $output = drupal_get_path_alias($path, $language);
       if ($output && $output != $path) {
         $document->path = $output;
-        $text .= ' ' . $output;
       }
     }
 
@@ -504,42 +503,19 @@ function apachesolr_node_to_document($ni
           // Don't index NULLs or empty strings
           if (isset($value['safe']) && strlen($value['safe'])) {
             if ($cck_info['multiple']) {
-              $document->setMultiValue($index_key, apachesolr_strip_ctl_chars($value['safe']));
+              $document->setMultiValue($index_key, apachesolr_clean_text($value['safe']));
             }
             else {
-              $document->$index_key = apachesolr_strip_ctl_chars($value['safe']);
+              $document->$index_key = apachesolr_clean_text($value['safe']);
             }
           }
         }
       }
     }
+    apachesolr_add_tags_to_document($document, $text);
+    apachesolr_add_taxonomy_to_document($document, $node);
 
-    // This is the string value of the title. Used for sorting.
-    // TODO  - use Solr copyfield directive.
-    $document->stitle = $node->title;
-
-    if (is_array($node->taxonomy)) {
-      foreach ($node->taxonomy as $term) {
-        // Double indexing of tids lets us do effecient searches (on tid)
-        // and do accurate per-vocabulary faceting.
-
-        // By including the ancestors to a term in the index we make
-        // sure that searches for general categories match specific
-        // categories, e.g. Fruit -> apple, a search for fruit will find
-        // content categorized with apple.
-        $ancestors = taxonomy_get_parents_all($term->tid);
-        foreach ($ancestors as $ancestor) {
-          $document->setMultiValue('tid', $ancestor->tid);
-          $document->setMultiValue('imfield_vid'. $ancestor->vid, $ancestor->tid);
-          $document->setMultiValue('vid', $ancestor->vid);
-          $document->setMultiValue('taxonomy_name', apachesolr_strip_ctl_chars($ancestor->name));
-          $text .= ' ' . $ancestor->name;
-        }
-      }
-    }
-    $document->text = apachesolr_clean_text($text);
-
-    // Let modules add to the document
+    // Let modules add to the document - TODO convert to drupal_alter().
     foreach (module_implements('apachesolr_update_index') as $module) {
       $function = $module .'_apachesolr_update_index';
       $function($document, $node);
@@ -548,6 +524,66 @@ function apachesolr_node_to_document($ni
   return $document;
 }
 
+/**
+ * Extract taxonomy from $node and add to dynamic fields.
+ */
+function apachesolr_add_taxonomy_to_document(&$document, $node) {
+  if (isset($node->taxonomy) && is_array($node->taxonomy)) {
+    foreach ($node->taxonomy as $term) {
+      // Double indexing of tids lets us do effecient searches (on tid)
+      // and do accurate per-vocabulary faceting.
+
+      // By including the ancestors to a term in the index we make
+      // sure that searches for general categories match specific
+      // categories, e.g. Fruit -> apple, a search for fruit will find
+      // content categorized with apple.
+      $ancestors = taxonomy_get_parents_all($term->tid);
+      foreach ($ancestors as $ancestor) {
+        $document->setMultiValue('tid', $ancestor->tid);
+        $document->setMultiValue('imfield_vid'. $ancestor->vid, $ancestor->tid);
+        $name = apachesolr_clean_text($ancestor->name);
+        $document->{'tsfield_vid'. $ancestor->vid .'_names'} .= $name;
+        // We index each name as a string for faceting.
+        // TODO - consider using the vocab name rather than vid in field
+        // construction for cross-site searching.
+        $document->setMultiValue('smfield_vid'. $ancestor->vid .'_name', $name);
+        $document->setMultiValue('vid', $ancestor->vid);
+        $document->taxonomy_names .= ' '. $name;
+       }
+    }
+  }
+}
+
+/**
+ * Extract HTML tag contents from $text and add to boost fields.
+ *
+ * $text must be stripped of control characters before hand.
+ */
+function apachesolr_add_tags_to_document(&$document, $text) {
+  $tags_to_index = variable_get('apachesolr_tags_to_index', array(
+    'h1' => 'tags_h1',
+    'h2' => 'tags_h2_h3',
+    'h3' => 'tags_h2_h3',
+    'h4' => 'tags_h4_h5_h6',
+    'h5' => 'tags_h4_h5_h6',
+    'h6' => 'tags_h4_h5_h6',
+    'u' => 'tags_inline',
+    'b' => 'tags_inline',
+    'i' => 'tags_inline',
+    'strong' => 'tags_inline',
+    'em' => 'tags_inline',
+    'a' => 'tags_a'
+  ));
+
+  // Strip off all ignored tags.
+  $text = strip_tags($text, '<'. implode('><', array_keys($tags_to_index)) .'>');
+
+  preg_match_all('@<('. implode('|', array_keys($tags_to_index)) .')[^>]*>(.*)</\1>@Ui', $text, $matches);
+  foreach ($matches[1] as $key => $tag) {
+    $document->{$tags_to_index[$tag]} .= ' '. $matches[2][$key];
+  }
+}
+
 function apachesolr_delete_node_from_index($node) {
   try {
     $solr = apachesolr_get_solr();
@@ -560,6 +596,19 @@ function apachesolr_delete_node_from_ind
 }
 
 /**
+ * Implementation of hook_cron().
+ */
+function apachesolr_cron() {
+  try {
+    $solr = apachesolr_get_solr();
+    $solr->clearCache();
+  }
+  catch (Exception $e) {
+    watchdog('Apache Solr', $e->getMessage(), NULL, WATCHDOG_ERROR);
+  }
+}
+
+/**
  * Implementation of hook_nodeapi().
  */
 function apachesolr_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
@@ -630,10 +679,14 @@ function apachesolr_block($op = 'list', 
             }
 
             $sort_links = array();
-            $path = 'search/' . arg(1) . '/' . $query->get_query();
+            $path = 'search/' . arg(1) . '/' . $query->get_query_basic();
+            $new_query = clone $query;
             foreach ($sorts as $type => $sort) {
               $new_sort = isset($solrsorts[$type]) ? $solrsorts[$type] == 'asc' ? 'desc' : 'asc' : $sort['default'];
-              $sort_links[] = theme('apachesolr_sort_link', $sort['name'], $path, $type == "relevancy" ? '' : "solrsort={$type} {$new_sort}", isset($solrsorts[$type]) ? $solrsorts[$type] : '');
+              $new_query->set_solrsort($type == "relevancy" ? '' : "solrsort={$type} {$new_sort}");
+              $active = isset($solrsorts[$type]) || ($type == "relevancy" && !$solrsorts);
+              $direction = isset($solrsorts[$type]) ? $solrsorts[$type] : '';
+              $sort_links[] = theme('apachesolr_sort_link', $sort['name'], $path, $new_query->get_url_querystring(), $active, $direction);
             }
             return array('subject' => t('Sort by'),
                          'content' => theme('apachesolr_sort_list', $sort_links));
@@ -681,12 +734,14 @@ function apachesolr_facet_block($respons
         $contains_active = TRUE;
         $new_query->remove_field($delta, $facet);
         // TODO: don't assume 'search' - find the real path.
-        $path = 'search/'. arg(1) .'/'. $new_query->get_query();
-        $unclick_link = theme('apachesolr_unclick_link', $path);
+        $path = 'search/'. arg(1) .'/'. $new_query->get_query_basic();
+        $querystring = $new_query->get_url_querystring();
+        $unclick_link = theme('apachesolr_unclick_link', $path, $querystring);
       }
       else {
         $new_query->add_field($delta, $facet);
-        $path = 'search/'. arg(1) .'/'. $new_query->get_query();
+        $path = 'search/'. arg(1) .'/'. $new_query->get_query_basic();
+        $querystring = $new_query->get_url_querystring();
       }
       $countsort = $count == 0 ? '' : 1 / $count;
       // if numdocs == 1 and !active, don't add.
@@ -694,7 +749,7 @@ function apachesolr_facet_block($respons
         // skip
       }
       else {
-        $items[$active ? $countsort . $facet : 1 + $countsort . $facet] = theme('apachesolr_facet_item', $facet_text, $count, $path, $active, $unclick_link, $response->numFound);
+        $items[$active ? $countsort . $facet : 1 + $countsort . $facet] = theme('apachesolr_facet_item', $facet_text, $count, $path, $querystring, $active, $unclick_link, $response->numFound);
       }
     }
     if (count($items) > 0) {
@@ -860,7 +915,7 @@ function apachesolr_static_response_cach
  * programmatically you can pass in different keys. If you don't pass in
  * any keys, search_get_keys() is used instead.
  */
-function apachesolr_drupal_query($keys = NULL, $reset = FALSE) {
+function apachesolr_drupal_query($keys = '', $filters = '', $solrsort = '', $reset = FALSE) {
   static $_queries;
 
   if ($reset) {
@@ -870,21 +925,27 @@ function apachesolr_drupal_query($keys =
   if (empty($keys)) {
     $keys = search_get_keys();
   }
+  if (empty($filters) && !empty($_GET['filters'])) {
+    $filters = check_plain($_GET['filters']); 
+  }
+  if (empty($solrsort) && !empty($_GET['solrsort'])) {
+    $solrsort = check_plain($_GET['solrsort']);
+  }
+  $index = $keys . '&filters=' . $filters;
 
-  if (empty($_queries) || empty($_queries[$keys])) {
+  if (empty($_queries) || empty($_queries[$index])) {
     list($module, $class) = variable_get('apachesolr_query_class', array('apachesolr', 'Solr_Base_Query'));
     include_once drupal_get_path('module', $module) .'/'. $class .'.php';
 
-    $solr = apachesolr_get_solr();
     try {
-      $_queries[$keys] = new $class($solr, $keys);
+      $_queries[$index] = new $class(apachesolr_get_solr(), $keys, $filters, $solrsort);
     }
     catch (Exception $e) {
       watchdog('Apache Solr', $e->getMessage(), NULL, WATCHDOG_ERROR);
       return;
     }
   }
-  return $_queries[$keys];
+  return $_queries[$index];
 }
 
 /**
@@ -962,10 +1023,10 @@ function apachesolr_cck_fields() {
 function apachesolr_theme() {
   return array(
     'apachesolr_facet_item' => array(
-      'arguments' => array('name' => NULL, 'count' => NULL, 'path' => NULL, 'active' => FALSE, 'unclick_link' => NULL),
+      'arguments' => array('name' => NULL, 'count' => NULL, 'path' => NULL, 'querystring' => '', 'active' => FALSE, 'unclick_link' => NULL, 'num_found' => NULL),
     ),
     'apachesolr_unclick_link' => array(
-      'arguments' => array('url' => NULL),
+      'arguments' => array('url' => NULL, 'querystring' => ''),
     ),
     'apachesolr_facet_list' => array(
       'arguments' => array('items' => NULL),
@@ -974,7 +1035,7 @@ function apachesolr_theme() {
       'arguments' => array('items' => NULL),
     ),
     'apachesolr_sort_link' => array(
-      'arguments' => array('text' => NULL, 'path' => NULL, 'query' => NULL, 'direction' => NULL),
+      'arguments' => array('text' => NULL, 'path' => NULL, 'querystring' => '', 'active' => FALSE, 'direction' => ''),
     ),
     'apachesolr_breadcrumb_type' => array(
       'arguments' => array('type' => NULL),
@@ -982,7 +1043,7 @@ function apachesolr_theme() {
   );
 }
 
-function theme_apachesolr_facet_item($name, $count, $path, $active = FALSE, $unclick_link = NULL, $num_found = NULL) {
+function theme_apachesolr_facet_item($name, $count, $path, $querystring = '', $active = FALSE, $unclick_link = NULL, $num_found = NULL) {
   $attributes = array();
   if ($active) {
     $attributes['class'] = 'active';
@@ -991,20 +1052,34 @@ function theme_apachesolr_facet_item($na
     return $unclick_link . ' '. check_plain($name);
   }
   else {
-    return l($name ." ($count)",  $path, array('attributes' => $attributes, 'query' => isset($_GET['solrsort']) ? "solrsort=" . check_plain($_GET['solrsort']) : FALSE));
+    return apachesolr_l($name ." ($count)",  $path, array('attributes' => $attributes, 'query' => $querystring));
   }
 }
 
-function theme_apachesolr_unclick_link($path) {
-  return l("(-)", $path, array('query' => isset($_GET['solrsort']) ? "solrsort=" . check_plain($_GET['solrsort']) : FALSE));
+function apachesolr_l($text, $path, $options = array()) {
+  // Merge in defaults.
+  $options += array(
+    'attributes' => array(),
+  );
+
+  return '<a href="'. check_url(url($path, $options)) .'"'. drupal_attributes($options['attributes']) .'>'. check_plain($text) .'</a>';
+}
+
+
+function theme_apachesolr_unclick_link($path, $querystring = '') {
+  return apachesolr_l("(-)", $path, array('query' => $querystring));
 }
 
-function theme_apachesolr_sort_link($text, $path, $query, $direction = NULL) {
+function theme_apachesolr_sort_link($text, $path, $querystring = '', $active = FALSE, $direction = '') {
   $icon = '';
+  $attributes = array();
   if ($direction) {
-    $icon = theme('tablesort_indicator', $direction);
+    $icon = ' '. theme('tablesort_indicator', $direction);
+  }
+  if ($active) {
+    $attributes['class'] = 'active';
   }
-  return $icon . ' ' . l($text, $path, array('query' => $query));
+  return $icon . apachesolr_l($text, $path, array('attributes' => $attributes, 'query' => $querystring));
 }
 
 function theme_apachesolr_facet_list($items) {
Index: apachesolr_search.admin.inc
===================================================================
RCS file: apachesolr_search.admin.inc
diff -N apachesolr_search.admin.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ apachesolr_search.admin.inc	8 Dec 2008 21:12:23 -0000
@@ -0,0 +1,80 @@
+<?php
+// $Id: apachesolr_search.module,v 1.1.2.6.2.40 2008/12/06 01:23:50 pwolanin Exp $
+
+/**
+ * @file
+ *   Administrative settings for searching.
+ */
+
+/**
+ * Menu callback - the settings form.
+ */
+function apachesolr_search_settings_page() {
+  return drupal_get_form('apachesolr_search_settings_form');
+}
+
+/**
+ * Form builder function to set query field weights.
+ */
+function apachesolr_search_settings_form() {
+  $form = array();
+
+  // get the current weights
+  $qf = variable_get('apachesolr_search_query_fields', array());
+  $weights = array();
+  $weights['0'] = t('Omit');
+  $weights += drupal_map_assoc(array('0.1', '0.2', '0.5', '1.0', '2.0', '3.0', '5.0', '8.0', '13.0', '21.0'));
+  // Note - we have default values set in solrconfig.xml, which will operate when 
+  // none are set.
+  $defaults = array(
+    'body' => '0.5',
+    'title' => '13.0',
+    'name' => '5.0',
+    'taxonomy_names' => '2.0',
+    'tags_h1' => '21.0',
+    'tags_h2_h3' => '13.0',
+    'tags_h4_h5_h6' => '5.0',
+    'tags_inline' => '2.0',
+    'tags_a' => '2.0',
+  );
+  if (!$qf) {
+    $qf = $defaults;
+  }
+  // try to fetch the schema fields
+  $solr = apachesolr_get_solr();
+  $fields = $solr->getFields();
+  if ($fields) {
+
+    $form['apachesolr_search_query_fields'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Field weights'),
+      '#collapsible' => TRUE,
+      '#collapsed' => FALSE,
+      '#tree' => TRUE,
+      '#description' => t('Specify here which fields are more important when searching. Give a field a bigger numeric value to make it more important.  If you omit a field, it will not be searched for keywords.'),
+    );
+    // Make sure all the default fields are included, even if they have no indexed content.
+    foreach ($defaults as $field_name => $weight) {
+      $form['apachesolr_search_query_fields'][$field_name] = array(
+        '#type' => 'select',
+        '#options' => $weights,
+        '#title' => t('Weight for %field_name', array('%field_name' => $field_name)),
+        '#default_value' => isset($qf[$field_name]) ? $qf[$field_name] : $defaults[$field_name],
+      );
+    }
+    foreach ($fields as $field_name => $field) {
+      $form['apachesolr_search_query_fields'][$field_name] = array(
+        '#access' => $field->type == 'text',
+        '#type' => 'select',
+        '#options' => $weights,
+        '#title' => t('Weight for %field_name', array('%field_name' => $field_name)),
+        '#default_value' => isset($qf[$field_name]) ? $qf[$field_name] : '0',
+      );
+    }
+
+    ksort($form['apachesolr_search_query_fields']);
+  }
+
+  return system_settings_form($form);
+}
+
Index: apachesolr_search.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr_search.module,v
retrieving revision 1.1.2.6.2.40
diff -u -p -r1.1.2.6.2.40 apachesolr_search.module
--- apachesolr_search.module	6 Dec 2008 01:23:50 -0000	1.1.2.6.2.40
+++ apachesolr_search.module	8 Dec 2008 21:12:23 -0000
@@ -29,6 +29,22 @@ function apachesolr_search_help($section
 }
 
 /**
+ * Implementation of hook_menu().
+ */
+function apachesolr_search_menu() {
+  $items['admin/settings/apachesolr/query_fields'] = array(
+    'title'            => 'Query field settings',
+    'page callback'    => 'apachesolr_search_settings_page',
+    'access arguments' => array('administer site configuration'),
+    'weight'           => 1,
+    'type'             => MENU_LOCAL_TASK,
+    'file'             => 'apachesolr_search.admin.inc',
+  );
+
+  return $items;
+}
+
+/**
  * Implementation of hook_update_index().
  */
 function apachesolr_search_update_index() {
@@ -112,6 +128,20 @@ function apachesolr_search_search($op = 
         }
         $page = isset($_GET['page']) ? $_GET['page'] : 0;
         $params['start'] = $page * $params['rows'];
+        // This is the object that does the communication with the solr server.
+        $solr = apachesolr_get_solr();
+
+        // Note - we have query fields set in solrconfig.xml, which will operate when 
+        // none are set.
+        $qf = variable_get('apachesolr_search_query_fields', array());
+        $fields = $solr->getFields();
+        if ($qf && $fields) {
+          foreach ($fields as $field_name => $field) {
+            if (!empty($qf[$field_name])) {
+              $params['qf'][] = $field_name . '^'. $qf[$field_name];
+            }
+          }
+        }
 
         /**
          * This hook allows modules to modify the query are params objects.
@@ -126,6 +156,7 @@ function apachesolr_search_search($op = 
          * }
          * </code>
          */
+        // TODO - convert to drupal_alter().
         foreach (module_implements('apachesolr_modify_query') as $module) {
           $function_name = "{$module}_apachesolr_modify_query";
           $function_name($query, $params);
@@ -133,9 +164,10 @@ function apachesolr_search_search($op = 
         if (!$query) {
           return array();
         }
-        // This is the object that does the communication with the solr server.
-        $solr = apachesolr_get_solr();
-        $response = $solr->search($query->get_query(), $params['start'], $params['rows'], $params);
+        // An arry of fq parameters.
+        $params['fq'] = $query->get_fq();
+
+        $response = $solr->search($query->get_query_basic(), $params['start'], $params['rows'], $params);
         // The response is cached so that it is accessible to the blocks and anything
         // else that needs it beyond the initial search.
         apachesolr_static_response_cache($response);
@@ -175,7 +207,7 @@ function apachesolr_search_search($op = 
       } // try
       catch (Exception $e) {
         watchdog('Apache Solr', $e->getMessage(), NULL, WATCHDOG_ERROR);
-        apachesolr_failure(t('Solr search'), is_null($query) ? $keys : $query->get_query());
+        apachesolr_failure(t('Solr search'), is_null($query) ? $keys : $query->get_query_basic());
       }
       break;
   } // switch
@@ -239,12 +271,14 @@ function apachesolr_search_block($op = '
               if ($active = $query->has_field('tid', $tid)) {
                 $contains_active = TRUE;
                 $new_query->remove_field('tid', $term->tid);
-                $path = 'search/' . arg(1) . '/' . $new_query->get_query();
-                $unclick_link = theme('apachesolr_unclick_link', $path);
+                $path = 'search/' . arg(1) . '/' . $new_query->get_query_basic();
+                $querystring = $new_query->get_url_querystring();
+                $unclick_link = theme('apachesolr_unclick_link', $path, $querystring);
               }
               else {
                 $new_query->add_field('tid', $term->tid);
-                $path = 'search/' . arg(1) . '/' . $new_query->get_query();
+                $path = 'search/' . arg(1) . '/' . $new_query->get_query_basic();
+                $querystring = $new_query->get_url_querystring();
               }
               $countsort = $count == 0 ? '' : 1 / $count;
               // if numdocs == 1 and !active, don't add.
@@ -252,8 +286,7 @@ function apachesolr_search_block($op = '
                 // skip
               }
               else {
-                $terms[$term->vid][$active ? $countsort . $term->name : 1 + $countsort . $term->name] =
-                    theme('apachesolr_facet_item', $term->name, $count, $path, $active, $unclick_link, $response->numFound);
+                $terms[$term->vid][$active ? $countsort . $term->name : 1 + $countsort . $term->name] = theme('apachesolr_facet_item', $term->name, $count, $path, $querystring, $active, $unclick_link, $response->numFound);
               }
             }
           }
@@ -273,26 +306,29 @@ function apachesolr_search_block($op = '
 
         switch ($delta) {
           case 'currentsearch':
-            $block_title = t('Current search');
-            $links = array();
             $fields = $query->get_fields();
+            $search_keys = $query->get_query_basic();
+            $path = 'search/' . arg(1) . '/' . $search_keys;
+            $options = array();
+            if (!$fields) {
+              $options['attributes']['class'] = 'active';
+            }
+            $links[] = apachesolr_l($search_keys, $path, $options);
             foreach($fields as $field) {
-              $new_query = clone $query;
               if ($field['#name']) {
+                $new_query = clone $query;
                 $new_query->remove_field($field['#name'], $field['#value']);
-                $path = 'search/'. arg(1) .'/'. $new_query->get_query();
-              } else {
-                $query_without_keywords = preg_replace('/(^| )([a-z0-9][^:]+)($| )/i', ' ', $query->get_query());
-                $path = 'search/'. arg(1) .'/'. $query_without_keywords;
-              }             
-              $unclick_link = theme('apachesolr_unclick_link', $path);
-              if (! $fielddisplay = theme("apachesolr_breadcrumb_". $field['#name'], $field['#value'])) {
-                $fielddisplay = $field['#value'];
-              }
-              $links[] = theme('apachesolr_facet_item', $fielddisplay, $count, $path, $active, $unclick_link, $response->numFound);
+                $path = 'search/'. arg(1) .'/'. $new_query->get_query_basic();
+                $querystring = $new_query->get_url_querystring();
+                $unclick_link = theme('apachesolr_unclick_link', $path, $querystring);
+                if (! $fielddisplay = theme("apachesolr_breadcrumb_". $field['#name'], $field['#value'])) {
+                  $fielddisplay = $field['#value'];
+                }
+                $links[] = theme('apachesolr_facet_item', $fielddisplay, NULL, $path, $querystring, $active, $unclick_link, $response->numFound);
+              }            
             }
             $content = theme('apachesolr_currentsearch', $response->response->numFound, $links);
-            return array('subject' => $block_title,
+            return array('subject' => t('Current search'),
                          'content' => $content);
 
           case 'uid':
@@ -313,12 +349,14 @@ function apachesolr_search_block($op = '
                     if ($active = $query->has_field($index_key, $facet)) {
                       $contains_active = TRUE;
                       $new_query->remove_field($index_key, $facet);
-                      $path = 'search/'. arg(1) .'/'. $new_query->get_query();
-                      $unclick_link = theme('apachesolr_unclick_link', $path);
+                      $path = 'search/'. arg(1) .'/'. $new_query->get_query_basic();
+                      $querystring = $new_query->get_url_querystring();
+                      $unclick_link = theme('apachesolr_unclick_link', $path, $querystring);
                     }
                     else {
                       $new_query->add_field($index_key, $facet);
-                      $path = 'search/'. arg(1) .'/'. $new_query->get_query();
+                      $path = 'search/'. arg(1) .'/'. $new_query->get_query_basic();
+                      $querystring = $new_query->get_url_querystring();
                     }
                     $countsort = $count == 0 ? '' : 1 / $count;
                     // if numdocs == 1 and !active, don't add.
@@ -326,7 +364,7 @@ function apachesolr_search_block($op = '
                       // skip
                     }
                     else {
-                      $facets[$active ? $countsort . $facet : 1 + $countsort . $facet] = theme('apachesolr_facet_item', $facet, $count, $path, $active, $unclick_link, $response->numFound);
+                      $facets[$active ? $countsort . $facet : 1 + $countsort . $facet] = theme('apachesolr_facet_item', $facet, $count, $path, $querystring, $active, $unclick_link, $response->numFound);
                     }
                   }
                   if (!empty($facets)) {
@@ -401,7 +439,6 @@ function theme_apachesolr_breadcrumb_tid
   return $term->name;
 }
 
-
 /**
  * Return current search block contents
  */
Index: schema.xml
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/schema.xml,v
retrieving revision 1.1.2.1.2.13
diff -u -p -r1.1.2.1.2.13 schema.xml
--- schema.xml	2 Dec 2008 01:53:17 -0000	1.1.2.1.2.13
+++ schema.xml	8 Dec 2008 21:12:23 -0000
@@ -254,7 +254,7 @@
    <field name="url" type="string" indexed="true" stored="true"/>
    <field name="title" type="text" indexed="true" stored="true" termVectors="true"/>
    <field name="stitle" type="string" indexed="true" stored="true"/>
-   <field name="body" type="text" indexed="false" stored="true"/>
+   <field name="body" type="text" indexed="true" stored="true" termVectors="true"/>
    <field name="type" type="string" indexed="true" stored="true"/>
    <field name="path" type="text" indexed="true" stored="true" termVectors="true"/>
    <field name="uid"  type="integer" indexed="true" stored="true"/>
@@ -265,13 +265,21 @@
    <field name="comment_count" type="integer" indexed="true" stored="true"/>
    <field name="tid"  type="integer" indexed="true" stored="true" multiValued="true"/>
    <field name="vid"  type="integer" indexed="true" stored="true" multiValued="true"/>
-   <field name="taxonomy_name" type="text" indexed="true" stored="true" multiValued="true" termVectors="true"/>
-   <field name="text" type="text" indexed="true" stored="false" termVectors="true"/>
+   <field name="taxonomy_names" type="text" indexed="true" stored="true" termVectors="true"/>
    <field name="language" type="string" indexed="true" stored="true"/>
-
-   <!-- Here, default is used to create a "timestamp" field indicating
-        When each document was indexed.
-     -->
+   <!-- The string version of the title is used for sorting -->
+   <copyField source="title" dest="stitle"/>
+   <!-- A set of fields to contain text (like like tag contents or taxonomy
+        terms from a preferred vocabulary) which we can boost at query time -->
+
+   <field name="tags_h1" type="text" indexed="true" stored="false"/>
+   <field name="tags_h2_h3" type="text" indexed="true" stored="false"/>
+   <field name="tags_h4_h5_h6" type="text" indexed="true" stored="false"/>
+   <field name="tags_a" type="text" indexed="true" stored="false"/>
+   <!-- Inline tags are typically u, b, i, em, strong -->
+   <field name="tags_inline" type="text" indexed="true" stored="false"/>
+   <!-- Here, default is used to create a "timestamp" field indicating 
+        when each document was indexed.-->
    <field name="timestamp" type="date" indexed="true" stored="true" default="NOW" multiValued="false"/>
 
 
@@ -283,7 +291,6 @@
         Longer patterns will be matched first.  if equal size patterns
         both match, the first appearing in the schema will be used.  -->
 
-   <!-- <dynamicField name="*-l"  type="slong"   indexed="true"  stored="true"/> -->
    <dynamicField name="isfield*"  type="integer" indexed="true"  stored="true" multiValued="false"/>
    <dynamicField name="imfield*"  type="integer" indexed="true"  stored="true" multiValued="true"/>
    <dynamicField name="sisfield*" type="sint"    indexed="true"  stored="true" multiValued="false"/>
@@ -317,7 +324,7 @@
  <uniqueKey>id</uniqueKey>
 
  <!-- field for the QueryParser to use when an explicit fieldname is absent -->
- <defaultSearchField>text</defaultSearchField>
+ <defaultSearchField>body</defaultSearchField>
 
  <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
  <solrQueryParser defaultOperator="AND"/>
Index: solrconfig.xml
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/Attic/solrconfig.xml,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 solrconfig.xml
--- solrconfig.xml	30 Nov 2008 21:13:27 -0000	1.1.2.1
+++ solrconfig.xml	8 Dec 2008 21:12:23 -0000
@@ -357,7 +357,7 @@
      If no qt is defined, the requestHandler that declares default="true"
      will be used.
   -->
-  <requestHandler name="standard" class="solr.SearchHandler" default="true">
+  <requestHandler name="standard" class="solr.SearchHandler">
     <!-- default values for query parameters -->
      <lst name="defaults">
        <str name="echoParams">explicit</str>
@@ -380,38 +380,41 @@
     <lst name="defaults">
      <str name="defType">dismax</str>
      <str name="echoParams">explicit</str>
+    </lst>
+  </requestHandler>
+
+  <!-- Note how you can register the same handler multiple times with
+       different names (and different init parameters)
+    -->
+  <requestHandler name="drupal" class="solr.SearchHandler" default="true">
+    <lst name="defaults">
+     <str name="defType">dismax</str>
+     <str name="echoParams">all</str>
      <float name="tie">0.01</float>
      <str name="qf">
-        text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4
+        body^0.5 title^13.0 name^5.0 taxonomy_names^2.0 tags_h1^21.0 tags_h2_h3^13.0 tags_h4_h5_h6^5.0 tags_inline^2.0 tags_a^2.0
      </str>
      <str name="pf">
-        text^0.2 features^1.1 name^1.5 manu^1.4 manu_exact^1.9
-     </str>
-     <str name="bf">
-        ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3
-     </str>
-     <str name="fl">
-        id,name,price,score
+        body^2.0 title^8.0
      </str>
+     <int name="ps">100</int>
      <str name="mm">
-        2&lt;-1 5&lt;-2 6&lt;90%
+        2&lt;-35%
      </str>
-     <int name="ps">100</int>
-     <str name="q.alt">*:*</str>
-     <!-- example highlighter config, enable per-query with hl=true -->     
-     <str name="hl.fl">text features name</str>
-     <!-- for this field, we want no fragmenting, just highlighting -->
-     <str name="f.name.hl.fragsize">0</str>
-     <!-- instructs Solr to return the field itself if no query terms are
-          found -->
-     <str name="f.name.hl.alternateField">name</str>
-     <str name="f.text.hl.fragmenter">regex</str> <!-- defined below -->
+
+   <!-- example highlighter config, enable per-query with hl=true -->     
+     <str name="hl">true</str>
+     <str name="hl.fl">body</str>
+     <int name="hl.snippets">3</int>
+     <str name="hl.mergeContiguous">true</str>
+   <!-- instructs Solr to return the field itself if no query terms are
+        found -->
+     <str name="f.body.hl.alternateField">body</str>
+     <str name="f.body.hl.maxAlternateFieldLength">256</str>
+     <str name="f.body.hl.fragmenter">regex</str> <!-- defined below -->
     </lst>
   </requestHandler>
 
-  <!-- Note how you can register the same handler multiple times with
-       different names (and different init parameters)
-    -->
   <requestHandler name="partitioned" class="solr.SearchHandler" >
     <lst name="defaults">
      <str name="defType">dismax</str>
@@ -643,8 +646,8 @@
    <!-- Configure the standard formatter -->
    <formatter name="html" class="org.apache.solr.highlight.HtmlFormatter" default="true">
     <lst name="defaults">
-     <str name="hl.simple.pre"><![CDATA[<em>]]></str>
-     <str name="hl.simple.post"><![CDATA[</em>]]></str>
+     <str name="hl.simple.pre"><![CDATA[<strong>]]></str>
+     <str name="hl.simple.post"><![CDATA[</strong>]]></str>
     </lst>
    </formatter>
   </highlighting>
Index: Solr_Base_Query.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/Solr_Base_Query.php,v
retrieving revision 1.1.4.13
diff -u -p -r1.1.4.13 Solr_Base_Query.php
--- Solr_Base_Query.php	4 Dec 2008 17:04:43 -0000	1.1.4.13
+++ Solr_Base_Query.php	8 Dec 2008 21:12:23 -0000
@@ -11,15 +11,15 @@ class Solr_Base_Query {
    *
    * Extract a module-specific search option from a search query. e.g. 'type:book'
    */
-  static function query_extract($keys, $option) {
+  static function query_extract($filters, $option) {
     $pattern = '/(^| )'. $option .':(\"([^\"]*)\")/i';
-    preg_match_all($pattern, $keys, $matches);
+    preg_match_all($pattern, $filters, $matches);
     if (!empty($matches[2])) {
       // The preg_replace removes beginning and trailing quotations.
       return preg_replace('/^"|"$/', '', $matches[2]);
     }
     $pattern = '/(^| )'. $option .':([^ ]*)/i';
-    if (preg_match_all($pattern, $keys, $matches)) {
+    if (preg_match_all($pattern, $filters, $matches)) {
       if (!empty($matches[2])) {
         return $matches[2];
       }
@@ -27,18 +27,18 @@ class Solr_Base_Query {
   }
 
   /**
-   * Replaces all occurances of $option in $keys.
+   * Replaces all occurances of $option in $filters.
    */
-  static function query_replace($keys, $option) {
-    $matches = Solr_Base_Query::query_extract($keys, $option);
+  static function query_replace($filters, $option) {
+    $matches = self::query_extract($filters, $option);
     if (count($matches) > 0) {
       foreach ($matches as $match) {
         // TODO: Make some sort of name->value container object.
-        $found = Solr_Base_Query::make_field(array('#name' => $option, '#value' => $match));
-        $keys = str_replace($found, '', $keys);
+        $found = self::make_field(array('#name' => $option, '#value' => $match));
+        $filters = str_replace($found, '', $filters);
       }
     }
-    return $keys;
+    return $filters;
   }
 
   /**
@@ -50,99 +50,107 @@ class Solr_Base_Query {
       return implode(' ', array_filter(explode(' ', $values['#value']), 'trim'));
     }
     else {
-      // if the field value has spaces in it, wrap it in double quotes.
-      if (count(explode(' ', $values['#value'])) > 1) {
+      // if the field value has spaces, or : in it, wrap it in double quotes.
+      if (preg_match('/[ :]/', $values['#value'])) {
         $values['#value'] = '"'. $values['#value']. '"';
       }
       return $values['#name']. ':'. $values['#value'];
     }
   }
-
+  
   /**
-   * A keyed array where the key is a position integer and the value
-   * is an array with #name and #value properties.
+   * Static shared by all instances, used to increment ID numbers.
    */
-  private $_fields;
+  protected static $idCount = 0;
 
   /**
-   * An array of subqueries.
+   * Each query/subquery will have a unique ID
    */
-  private $_subqueries = array();
+  public $id;
 
   /**
-   * The query string.
+   * A keyed array where the key is a position integer and the value
+   * is an array with #name and #value properties.
    */
-  private $_query;
-
+  protected $fields;
+  protected $filters;
+  
   /**
-   * Should fields be AND'd or OR'd together?
+   * An array of subqueries.
    */
-  private $_field_operator;
+  protected $subqueries = array();
 
+  /**
+   * The query path (search keywords).
+   */
+  protected $querypath;
 
   /**
    * Apache_Solr_Service object
    */
-  var $solr;
+  protected $solr;
 
   /**
    * @param $solr
    *  An instantiated Apache_Solr_Service Object.
-   *  Can be instantiated from apachesolr_get_solr.
+   *  Can be instantiated from apachesolr_get_solr().
    *
-   * @param $querystring
+   * @param $querypath
    *   The string that a user would type into the search box. Suitable input
    *   may come from search_get_keys()
-   * @param $field_operator
-   *   An object level operator. AND is the implicit default. All segments will
-   *   be joined with this operator.
+   *
+   * @param $filterstring
+   *   Key and value pairs that are applied as a filter query.
+   *
+   * @param $sortstring
+   *   Visible string telling solr how to sort - added to output querystring.
    */
-  function __construct($solr, $querystring, $field_operator = "AND") {
+  function __construct($solr, $querypath, $filterstring, $sortstring) {
     $this->solr = $solr;
-    $this->set_field_operator($field_operator);
-    $this->_query = trim($querystring);
+    $this->querypath = trim($querypath);
+    $this->filters = trim($filterstring);
+    $this->solrsort = trim($sortstring);
+    $this->id = ++self::$idCount;
     $this->parse_query();
   }
 
-  function set_field_operator($field_operator = "AND") {
-    $this->_field_operator = $field_operator;
+  function __clone() {
+    $this->id = ++self::$idCount;
   }
 
   function add_field($field, $value) {
     // microtime guarantees that added fields come at the end of the query,
     // in order.
-    $this->_fields[microtime()] = array('#name' => $field, '#value' => trim($value));
-    $this->rebuild_query();
+    $this->fields[microtime()] = array('#name' => $field, '#value' => trim($value));
   }
 
   public function get_fields() {
-    return $this->_fields;
+    return $this->fields;
   }
 
-  function remove_field($name, $value = NULL) {
+  public function remove_field($name, $value = NULL) {
     // We can only remove named fields.
     if (empty($name)) {
       return;
     }
     if (empty($value)) {
-      foreach ($this->_fields as $pos => $values) {
+      foreach ($this->fields as $pos => $values) {
         if ($values['#name'] == $name) {
-          unset($this->_fields[$pos]);
+          unset($this->fields[$pos]);
         }
       }
     }
     else {
-      foreach ($this->_fields as $pos => $values) {
+      foreach ($this->fields as $pos => $values) {
         if ($values['#name'] == $name && $values['#value'] == $value) {
-          unset($this->_fields[$pos]);
+          unset($this->fields[$pos]);
         }
       }
     }
-    $this->rebuild_query();
   }
 
-  function has_field($name, $value) {
-    foreach ($this->_fields as $pos => $values) {
+  public function has_field($name, $value) {
+    foreach ($this->fields as $pos => $values) {
       if (!empty($values['#name']) && !empty($values['#value']) && $values['#name'] == $name && $values['#value'] == $value) {
         return TRUE;
       }
@@ -161,58 +169,74 @@ class Solr_Base_Query {
    * @param $operator
    *   'AND' or 'OR'
    */
-  function add_subquery(Solr_Base_Query $query, $operator = 'AND') {
-    $this->_subqueries[$query->get_query_basic()] = array('#query' => $query, '#operator' => $operator);
+  function add_subquery(Solr_Base_Query $query, $fq_operator = 'OR', $q_operator = 'AND') {
+    $this->subqueries[$query->id] = array('#query' => $query, '#fq_operator' => $fq_operator, '#q_operator' => $q_operator);
   }
 
   function remove_subquery(Solr_Base_Query $query) {
-    unset($this->_subqueries[$query->get_query_basic()]);
+    unset($this->subqueries[$query->id]);
   }
 
-  function remove_subqueries() {
-    $this->_subqueries = array();
+  public function remove_subqueries() {
+    $this->subqueries = array();
   }
 
-  function get_query() {
-    $this->rebuild_query();
-    return $this->_query;
+  public function set_solrsort($sortstring) {
+    $this->solrsort = trim($sortstring);
+  }
+  /**
+   * Return filters and sort in a form suitable for a query param to url().
+   */
+  public function get_url_querystring() {
+    $querystring = '';
+    if ($fq = $this->get_fq()) {
+      $querystring = 'filters='. implode(' ', $fq);
+    }
+    if ($this->solrsort) {
+      $querystring .= ($querystring) ? '&' . $this->solrsort : $this->solrsort;
+    }
+    return $querystring;
+  }
+
+  public function get_fq() {
+    return $this->rebuild_fq();
   }
 
   /**
    * A function to get just the keyword components of the query,
    * omitting any field:value portions.
    */
-  function get_query_basic() {
-    $nonames = array_filter($this->_fields, create_function('$a', 'return empty($a[\'#name\']);'));
-    $result = array();
-    foreach ($nonames as $pos => $field) {
-      $result[] = $field['#value'];
-    }
-    return implode(' ', $result);
+  public function get_query_basic() {
+    return $this->rebuild_query();
   }
 
-  function get_breadcrumb() {
+  public function get_breadcrumb() {
     // This encodes an assumption that the breadcrumb is always building off
     // of the current page. Could be a problem.
     $breadcrumb = menu_get_active_breadcrumb();
 
     // double check that the fields are ordered by position.
-    ksort($this->_fields);
+    ksort($this->fields);
 
     $progressive_crumb = array();
+    $search_keys = $this->get_query_basic();
     // TODO: Don't know if hardcoding this is going to come back to bite.
-    $base = 'search/'. arg(1). '/';
+    $base = 'search/'. arg(1) . '/' . $search_keys;
+    if ($search_keys) {
+      $breadcrumb[] = l($search_keys, $base);
+    }
 
-    foreach ($this->_fields as $field) {
+    foreach ($this->fields as $field) {
       $progressive_crumb[] = Solr_Base_Query::make_field($field);
+      $options = array('query' => 'filters=' . implode(' ', $progressive_crumb));
       if (empty($field['#name'])) {
-        $breadcrumb[] = l($field['#value'], $base. implode(' ', $progressive_crumb));
+        $breadcrumb[] = l($field['#value'], $base, $options);
       }
       else if ($themed = theme("apachesolr_breadcrumb_{$field['#name']}", $field['#value'])) {
-        $breadcrumb[] = l($themed, $base. implode(' ', $progressive_crumb));
+        $breadcrumb[] = l($themed, $base, $options);
       }
       else {
-        $breadcrumb[] = l($field['#value'], $base. implode(' ', $progressive_crumb));
+        $breadcrumb[] = l($field['#name'], $base, $options);
       }
     }
     // the last breadcrumb is the current page, so it shouldn't be a link.
@@ -223,8 +247,8 @@ class Solr_Base_Query {
   }
 
   protected function parse_query() {
-    $this->_fields = array();
-    $_keys = $this->_query;
+    $this->fields = array();
+    $filters = $this->filters;
 
     // Gets information about the fields already in solr index.
     $index_fields = $this->solr->getFields();
@@ -234,46 +258,52 @@ class Solr_Base_Query {
       do {
         // save the strlen so we can detect if it has changed at the bottom
         // of the do loop
-        $a = (int)strlen($_keys);
+        $a = (int)strlen($filters);
         // Get the values for $name
-        $values = Solr_Base_Query::query_extract($_keys, $name);
+        $values = Solr_Base_Query::query_extract($filters, $name);
         if (count($values) > 0) {
           foreach ($values as $value) {
             $found = Solr_Base_Query::make_field(array('#name' => $name, '#value' => $value));
-            $pos = strpos($this->_query, $found);
+            $pos = strpos($this->filters, $found);
             // $solr_keys and $solr_crumbs are keyed on $pos so that query order
             // is maintained. This is important for breadcrumbs.
-            $this->_fields[$pos] = array('#name' => $name, '#value' => trim($value));
+            $this->fields[$pos] = array('#name' => $name, '#value' => trim($value));
           }
-          // Update the local copy of $_keys by removing the key that was just found.
-          $_keys = trim(Solr_Base_Query::query_replace($_keys, $name));
+          // Update the local copy of $filters by removing the key that was just found.
+          $filters = trim(Solr_Base_Query::query_replace($filters, $name));
         }
         // Take new strlen to compare with $a.
-        $b = (int)strlen($_keys);
+        $b = (int)strlen($filters);
       } while ($a !== $b);
-
-      // Clean up by adding remaining keywords.
-      if (!empty($_keys)) {
-        $pos = strpos($this->_query, $_keys);
-        $this->_fields[$pos] = array('#name' => '', '#value' => trim($_keys));
-      }
     }
     // Even though the array has the right keys they are likely in the wrong
     // order. ksort() sorts the array by key while maintaining the key.
-    ksort($this->_fields);
+    ksort($this->fields);
   }
 
-  protected function rebuild_query() {
+  protected function rebuild_fq() {
     $fields = array();
-    foreach ($this->_fields as $pos => $values) {
+    foreach ($this->fields as $pos => $values) {
       $fields[] = Solr_Base_Query::make_field($values);
     }
-    $join_delim = $this->_field_operator == 'AND' ? ' ' : ' OR ';
-    $this->_query = trim(implode($join_delim, array_filter($fields, 'trim')));
-    foreach ($this->_subqueries as $id => $data) {
-      $operator = $data['#operator'];
-      $subquery = $data['#query']->get_query();
-      $this->_query .= " {$operator} ({$subquery})";
+    $fq = array_filter($fields, 'trim');
+    foreach ($this->subqueries as $id => $data) {
+      $subfq = $data['#query']->get_fq();
+      if ($subfq) {
+        $operator = $data['#fq_operator'];
+        $fq = $this->fq[] = implode(" {$operator} ", $subfq);
+      }
+    }
+    return $fq;
+  }
+
+  protected function rebuild_query() {
+    $query = $this->querypath;
+    foreach ($this->subqueries as $id => $data) {
+      $operator = $data['#q_operator'];
+      $subquery = $data['#query']->get_query_basic();
+      $query .= " {$operator} ({$subquery})";
     }
+    return $query;
   }
 }
Index: contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/contrib/apachesolr_nodeaccess/Attic/apachesolr_nodeaccess.module,v
retrieving revision 1.1.2.2
diff -u -p -r1.1.2.2 apachesolr_nodeaccess.module
--- contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module	2 Dec 2008 23:44:01 -0000	1.1.2.2
+++ contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module	8 Dec 2008 21:12:23 -0000
@@ -23,9 +23,8 @@ function apachesolr_nodeaccess_apachesol
 function _apachesolr_nodeaccess_build_subquery($account) {
   if (!user_access('administer nodes', $account) && count(module_implements('node_grants'))) {
     // Get node access perms
-    $node_access_query = "";
-    $node_access_query = apachesolr_drupal_query();
-    $node_access_query->set_field_operator("OR");
+    $query = apachesolr_drupal_query();
+    $node_access_query = clone $query;
 
     $grants = node_access_grants('view', $account);
     if (empty($grants)) {
@@ -58,7 +57,7 @@ function apachesolr_nodeaccess_apachesol
   }
 
   if (!empty($subquery)) {
-    $query->add_subquery($subquery, 'AND');
+    $query->add_subquery($subquery, 'OR');
   }
 }
 
