This is an old revision of the document!


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:
<?php
/**
 * @file
 * Contains methods to build and execute a solr query.
 * Depends on Apache_Solr_Php client.
 */
/**
 * Islandora Solr Query Processor
 * @todo Stop using global vars, start using this object's vars.
 *  The module itself should initially create an instance of this
 *  object and reference the query vars inside that object when calling
 *  other output display functions.
 */
class IslandoraSolrQueryProcessor
{
 
    ...
 
    function buildQuery($query, $fq = null, $dismax = null)
    {
        // Get pager variable
        $startPage = isset($_GET['page']) ? $_GET['page'] : 0;
        $this->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) . " <span class='islandora_solr_search_breadcrumb_super'>(" . l("x", $cutlink, array('attributes' => array('title' => "Remove " . $facet))) . ")</span>";
                    $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 = "<strong>" . $searchwords[0] . "</strong>";
                $nparole = count($searchwords);
                if ($nparole > 2) {
                    for ($i = 1; $i < ($nparole - 1); $i++) {
                        $elencoparole.= " " . $searchwords[$nparole - 1] . " " . "<strong>" . $searchwords[$i] . "</strong>";
                    }
                }
                $elencoparole.= " <span class='islandora_solr_search_breadcrumb_super'>°</span>";
                $breadcrumb[] = $elencoparole;
                //        $breadcrumb[] = l($queryval, $queryurl . "/-", array('attributes' => array('title' => $this->solrQuery))) .
                //            " <span class='islandora_solr_search_breadcrumb_super'>(" . l("x", $cutlink, array('attributes' => array('title' => "Remove " . $facet))) . ")</span>";
 
            }
        }
        //    $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'] = '<b>';
        $this->solrParams['hl.simple.post'] = '</b>';

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:
<?php
/**
 * @file
 * Contains methods to search solr and display results.  depends on Apache_Solr_Php client.
 */
/**
 * Islandora Solr Results
 */
class IslandoraSolrResults
{
   ...

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:
<?php
module_load_include('inc', 'islandora_solr_search', 'islandora_solr_search.admin');
module_load_include('inc', 'islandora_solr_search', 'includes/common');
module_load_include('inc', 'islandora_solr_search', 'IslandoraSolrQueryProcessor');
//$islandora_query;
$queryClass;
 
...
 
function islandora_solr_search_block_form_submit($form, &$form_state)
{
    global $queryClass;
    islandora_solr_search_init();
    $type_id = trim($form_state['values']['type']);
    $repeat = variable_get('islandora_solr_search_block_repeat', '3');
    $fedora_terms = array();
    $types = array();
    $booleans = array();
    for ($fieldNum = 1; $fieldNum <= $repeat; $fieldNum++) {
        if ($form_state['values']["fedora_terms$fieldNum"]) {
            $types[] = trim($form_state['values']["type$fieldNum"]);
            $fedora_terms[] = lesser_escape(trim($form_state['values']["fedora_terms$fieldNum"]));
        }
        $next = $fieldNum + 1;
        if ($form_state['values']["fedora_terms$next"] && $form_state['values']["fedora_terms$fieldNum"]) {
            $booleans[] = trim($form_state['values']["andor$fieldNum"]);
        }
    }
    for ($iteration = 0; $iteration < count($fedora_terms); $iteration++) {
        $searchString.= $types[$iteration] . ":" . $fedora_terms[$iteration] . " " . $booleans[$iteration] . " ";
    }   

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 islandorasolr.tar.gz (IslandoraSolrQueryProcessor.inc, IslandoraSolrResults.inc, islandora_solr_search.module)

 
 
frontend/fulltext.1381769019.txt.gz · Last modified: 2013/10/14 18:43 (external edit)

Developers: CNR IRCrES IT Office and Library
Giancarlo Birello (giancarlo.birello _@_ ircres.cnr.it) and Anna Perin (anna.perin _@_ ircres.cnr.it)
DigiBess is licensed under: Creative Commons License
Recent changes RSS feed Creative Commons License Valid XHTML 1.0 Valid CSS Driven by DokuWiki
Drupal Garland Theme for Dokuwiki