====== Multiple word search ====== Extend basic function to multiple word search (AND/OR condition). \\ Applicable only to **one** search block. \\ \\ **IMPORTANT NOTE** \\ \\ There is a bug in the solr-tomcat package which emits a required library (lucene-memory.jar) from Solr include path.\\ The bug only becomes apparent when you search for an exact match.\\ All that needs to be done is this: cd /usr/share/solr/WEB-INF/lib ln -s ../../../java/lucene-memory.jar lucene-memory.jar sudo service tomcat6 restart \\ \\ * Edit **''/sites/all/modules/islandora_solr_search/IslandoraSolrQueryProcessor.inc''**: solrLimit = variable_get('islandora_solr_search_num_of_results', 20); global $base_url, $facetArray; //used by facet block as well // -- cut here -- // Get display profile $islandora_solr_primary_display = variable_get('islandora_solr_primary_display', 'default'); $profiles = module_invoke_all("islandora_solr_primary_display"); if (!isset($profiles[$islandora_solr_primary_display])) { drupal_set_message("There is an error in the solr search configuration: the display profile is not found.", 'error'); return ""; } $profile = $profiles[$islandora_solr_primary_display]; // Include the file for the display profile require_once (drupal_get_path('module', $profile['module']) . '/' . $profile['file']); // Set display class and function vars $solrClass = $profile['class']; $solrFunction = $profile['function']; // -- end cut here -- //fix the query as some characters will break the search : and / slash are examples $this->solrQuery = restoreSlashes($query); if (empty($this->solrQuery)) { // $this->solrQuery = '%20'; //so we can allow empty queries to dismax } $facetArray = array(); $facetFields = ''; $rawFacetVals = variable_get("islandora_solr_search_block_facets", 'dc.subject,dc.type'); $facetArray = islandora_build_substitution_list($rawFacetVals); $facetFields = implode(",", array_keys($facetArray)); $facetlimit = variable_get('islandora_solr_search_block_facet_limit', '12'); $facetMinCount = variable_get('islandora_solr_search_block_facet_min_count', '2'); $requestHandler = variable_get("islandora_solr_search_block_request_handler", "standard"); $this->solrParams = array('facet' => 'true', 'facet.mincount' => $facetMinCount, 'facet.limit' => $facetlimit, 'qt' => $requestHandler, 'facet.field' => explode(',', $facetFields), //comma separated list configured in the block config ); $debugQuery = (variable_get('islandora_solr_search_debug_mode', 0) ? "true" : null); //any val incl. 'false' is treated as true by Solr // $fq = preg_replace('/PID:.*\*/', '', $fq); if ($fq != NULL && $fq != '-') { $fq = restoreSlashes($fq); //put the slash back $fqs = csv_explode(IslandoraSolrQueryProcessor::$facetSeparator, $fq, '"', true); //to filter by more then one facet we will separate them by~ for nowseparate them by~ for now $this->solrParams['fq'] = $fqs; $islandora_fq = replaceSlashes($fq); //remove the slash here as we will be using this in url's } if (empty($islandora_fq)) { $islandora_fq = '-'; } if ($dismax != NULL) { $this->solrDefType = $dismax; $this->solrParams['defType'] = $dismax; } $this->solrStart = max(0, $startPage) * $this->solrLimit; Tip // The breadcrumb should go in the display class $queryurl = "islandora/solr/search/" . replaceSlashes($this->solrQuery); $breadcrumb_fq = $islandora_fq; if (strcmp($islandora_fq, "-")) { foreach(csv_explode(IslandoraSolrQueryProcessor::$facetSeparator, $islandora_fq, '"', true) as $facet) { $field = substr($facet, 0, strpos($facet, ":")); if ($field !== "rels.hasModel") { $value = restoreSlashes(trim(substr($facet, strpos($facet, ":") + 1), '"')); $options = array('html' => true); $options['attributes']['title'] = $facet; $crumblink = $queryurl . "/" . $breadcrumb_fq . (empty($this->solrDefType) ? '' : '/' . $this->solrDefType); $cut_fq = $this->delete_filter($islandora_fq, $facet); $cutlink = $queryurl . "/" . $cut_fq . (empty($this->solrDefType) ? '' : '/' . $this->solrDefType); if (!strncmp("-", $facet, 1)) { $options['attributes']['class'] = "strikethrough"; } $breadcrumb[] = l($value, $crumblink, $options) . " (" . l("x", $cutlink, array('attributes' => array('title' => "Remove " . $facet))) . ")"; $breadcrumb_fq = $this->delete_filter($breadcrumb_fq, $facet); } } } if (!empty($this->solrQuery) && strcmp($this->solrQuery, ' ')) { $cutlink = "islandora/solr/search/ /" . $islandora_fq . "/dismax"; $queryval = $this->solrQuery; $tokens = explode(" ", $queryval); foreach($tokens as $token) { preg_match("/^.*:/", $token, $matches); $queryval = str_replace($matches[0], "", $queryval); } if ($queryval != '%252F') { $elencoparole = preg_replace('~\s+~', ' ', trim($queryval)); $searchwords = explode(" ", $elencoparole); $elencoparole = "" . $searchwords[0] . ""; $nparole = count($searchwords); if ($nparole > 2) { for ($i = 1; $i < ($nparole - 1); $i++) { $elencoparole.= " " . $searchwords[$nparole - 1] . " " . "" . $searchwords[$i] . ""; } } $elencoparole.= " °"; $breadcrumb[] = $elencoparole; // $breadcrumb[] = l($queryval, $queryurl . "/-", array('attributes' => array('title' => $this->solrQuery))) . // " (" . l("x", $cutlink, array('attributes' => array('title' => "Remove " . $facet))) . ")"; } } // $breadcrumb[] = l(t('Home'), NULL); $breadcrumb[] = "Search"; if (!empty($breadcrumb)) $breadcrumb = array_reverse($breadcrumb); drupal_set_breadcrumb($breadcrumb); $this->solrFilters = $islandora_fq; // if (strpos($fq, "rels.hasModel%253AbookCModel") === FALSE) { // if ($fq) { // $fq .= $this->facetSeparator; // } // $fq = "rels.hasModel%253AbookCModel"; // } // At this point let's invoke a hook for third-party modules to mess about // with the query parameters if they need to. Third party modules may alter // this object's query parameters if they wish. // module_invoke_all("islandora_solr_search_query_processor", &$this); return; } /** * Execute the query * @return type */ function executeQuery() { // //////////////////////////////////////////////////////////////////////////// // // Right here the function should be split. One function to execute the query, // // another to set up pager variables and generate display. // // //////////////////////////////////////////////////////////////////////////// // $url = variable_get('islandora_solr_search_block_url', 'http://localhost:8080/solr'); $pathParts = parse_url($url); $solr = new Apache_Solr_Service($pathParts['host'], $pathParts['port'], $pathParts['path'] . '/'); $solr->setCreateDocuments(0); $this->solrParams['hl'] = 'true'; $this->solrParams['hl.fl'] = '*'; $this->solrParams['hl.requireFieldMatch'] = 'true'; $this->solrParams['hl.snippets'] = '10'; $this->solrParams['hl.simple.pre'] = ''; $this->solrParams['hl.simple.post'] = ''; Tip $bcksolrQuery = $this->solrQuery; $bcksolrQuery = preg_replace('~\s+~', ' ', trim($bcksolrQuery)); $termini = explode(":", $bcksolrQuery); $parole = explode(" ", trim($termini[1])); $numeroparole = count($parole); $bcksolrQuery = ""; $bcksolrQuery = "(" . $termini[0] . ":" . $parole[0] . ")"; if ($numeroparole > 1) { for ($i = 1; $i < $numeroparole; $i++) { $bcksolrQuery = $bcksolrQuery . $termini[2] . "(" . $termini[0] . ":" . $parole[$i] . ")"; } } // This is where the query gets executed and output starts being created. try { // $results = $solr->search($this->solrQuery, $this->solrStart, $this->solrLimit, $this->solrParams); $results = $solr->search($bcksolrQuery, $this->solrStart, $this->solrLimit, $this->solrParams); } catch(Exception $e) { drupal_set_message(t('error searching ') . $e->getMessage()); } $this->solrResult = $results; if (empty($results)) { drupal_set_message(t('Error searching solr index. Is the solr search block configured properly?'), 'error'); return; } unset($results); unset($solr); return; } ... } * Edit **''/sites/all/modules/islandora_solr_search/IslandoraSolrResults.inc''**: Tip /** * Build solr search form * @param type $repeat * @param type $pathToSearchTerms * @param type $query * @return string */ function build_solr_search_form($repeat = NULL, $pathToSearchTerms = NULL, $query = NULL) { $types = array(); $terms = trim(variable_get('islandora_solr_searchterms', 'dc.title ~ Title,dc.subject ~ Subject')); $termsArray = preg_split('/[\n]/', $terms); foreach($termsArray as $term) { $vals = split('~', $term); if (!$vals[1]) { $vals[1] = $vals[0]; } $types[trim($vals[0]) ] = trim($vals[1]); } $queryArray = NULL; if (isset($query)) { $termini = explode(":", $query); $andOrs[] = trim($termini[2]); $queryArray = preg_split('/( OR | AND )/', $query, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); // foreach ($queryArray as $key => $val) { // if ($val === ' OR ' || $val === ' AND ') { // $andOrs[] = trim($val); // that is, just 'OR' or 'AND' // unset($queryArray[$key]); //remove that from the array // } // } $queryArray = array_values($queryArray); } $andOrArray = array('AND' => 'and', 'OR' => 'or',); $form = array(); if (!isset($repeat)) { $repeat = variable_get('islandora_solr_search_block_repeat', '3'); } $var0 = explode(':', $queryArray[0]); $form['search_type']['type1'] = array('#title' => 'Field', '#type' => 'select', '#options' => $types, '#default_value' => trim($var0[0])); $form['fedora_terms1'] = array('#size' => '24', '#type' => 'textfield', '#title' => 'One or more words', '#default_value' => (count($var0) >= 2 ? restoreSlashes(trim($var0[1], '()')) : ''),); // if ($repeat > 1 && $repeat < 9) { //don't want less then 2 or more then 9 if ($repeat > 0 && $repeat < 9) { //don't want less then 2 or more then 9 // for ($i = 2; $i < $repeat + 1; $i++) { for ($i = 1; $i < $repeat + 1; $i++) { $t = $i - 1; // $j = $i - 2; $j = $i - 1; $andorj = (isset($andOrs[$j]) ? $andOrs[$j] : 'AND'); $field_and_term = explode(':', $queryArray[$t]); $form["andor$t"] = array('#title' => 'Words boolean', '#type' => 'select', '#default_value' => $andorj, '#options' => $andOrArray); /* $form['search_type']["type$i"] = array( '#title' => '', '#type' => 'select', '#options' => $types, '#default_value' => trim($field_and_term[0]) ); $form["fedora_terms$i"] = array( '#size' => '24', '#type' => 'textfield', '#title' => '', '#default_value' => (count($field_and_term) >= 2 ? trim($field_and_term[1], '()') : ''), ); */ } } $form['submit'] = array('#type' => 'submit', '#value' => t('Search')); return $form; } ... /** * Theme solr search form * @param type $form * @return type */ function theme_solr_search_form($form) { if (!isset($repeat)) { $repeat = variable_get('islandora_solr_search_block_repeat', '3'); } $output = drupal_render($form['search_type']['type1']); $output.= drupal_render($form['fedora_terms1']); // $output.= drupal_render($form['andor1']) . drupal_render($form['search_type']['type2']); $output.= drupal_render($form['andor1']); /* $output .= drupal_render($form['fedora_terms2']); if ($repeat > 2 && $repeat < 9) { for ($i = 3; $i < $repeat + 1; $i++) { $t = $i - 1; $output .= drupal_render($form["andor$t"]) . drupal_render($form['search_type']["type$i"]); $output .= drupal_render($form["fedora_terms$i"]); } } $output .= drupal_render($form['submit']); */ $output.= drupal_render($form); return $output; } } * Edit **''/sites/all/modules/islandora_solr_search/islandora_solr_search.module''**: Tip // append AND or OR at the end of string $searchString.= ":" . trim($form_state['values']["andor0"]); // $searchString = trim($searchString); $searchString = htmlspecialchars(drupal_urlencode($searchString), ENT_QUOTES, 'utf-8', false); $searchString = str_replace('/', '~slsh~', $searchString); //replace the slash so url doesn't break drupal_goto("islandora/solr/search/$searchString/-"); } ... Download {{:frontend:islandorasolr.tar.gz|}} (IslandoraSolrQueryProcessor.inc, IslandoraSolrResults.inc, islandora_solr_search.module)