Example #1
0
 /**
  *
  */
 public function get_query_string()
 {
     if (!$this->query) {
         return null;
     }
     return $this->query->get('query_string');
 }
Example #2
0
 /**
  * @param nc_search_query $query
  * @return string|null
  */
 public function translate(nc_search_query $query)
 {
     $root = $query->parse();
     // empty query?
     if ($root instanceof nc_search_query_expression_empty) {
         return null;
     }
     // queries with only excluded terms are forbidden
     if ($root->is_excluded() || $root instanceof nc_search_query_expression_not) {
         return null;
     }
     // initialize variables used for a translation of the query
     $this->query_builder = $builder = new nc_search_provider_index_querybuilder($query, $this);
     $this->stack = array();
     $this->unknown_required_terms = array();
     $this->can_skip_fts_query = false;
     $this->implicit_field_match = $this->expression_requires_implicit_match($root);
     // get language filters chain to use in this.translate_term() etc.
     $language = $query->get('language');
     if (!$language) {
         $language = nc_Core::get_object()->lang->detect_lang();
     }
     $query_context = new nc_search_context(array("search_provider" => get_class($this->provider), "language" => $language, "action" => "searching"));
     $this->text_filters = nc_search_extension_manager::get('nc_search_language_filter', $query_context)->stop_on(array());
     // Ready to go!
     // translate the expression tree
     $index_query = $this->dispatch_translate($root);
     if (!$this->can_skip_fts_query) {
         // interval search at the root for a numeric field
         // index query is required almost always
         if (!strlen($index_query)) {
             return null;
         }
         // e.g. if query string consists of stop words
         if ($index_query == "____" || $index_query == "(____)") {
             // empty query
             return null;
         }
     }
     // set query for the combined index in the query builder
     if ($index_query && !$root->get_field()) {
         $builder->set_index_match($index_query);
     }
     // there are required terms that are not in the index, so don’t make a query
     if ($this->unknown_required_terms) {
         return null;
     }
     // использовать временную таблицу для уточняющих запросов при поиске фраз?
     $use_temp_table = !nc_search::get_setting('DatabaseIndex_AlwaysGetTotalCount') && $this->expression_has_phrase($root);
     // return SQL query string
     $result = $builder->get_sql_query($use_temp_table);
     return $result;
 }
Example #3
0
 /**
  * Выполнение запроса
  * @param nc_search_query $query
  * @param boolean $should_highlight
  * @return nc_search_result
  */
 public function find(nc_search_query $query, $should_highlight = true)
 {
     $db = $this->get_db();
     $id_list = "0";
     $translator = new nc_search_provider_index_translator($this);
     // get IDs
     $select_ids_query = $query->translate($translator);
     $limit = (int) $query->get('limit');
     $offset = (int) $query->get('offset');
     $total_hits_unknown = false;
     if ($select_ids_query) {
         // neither null nor empty string
         $db->last_error = null;
         if (is_array($select_ids_query)) {
             // will need to create a temporary table; no final row count
             $prefilter_query = $select_ids_query["prefilter"];
             $refinement_query = $select_ids_query["refinement"];
             $query_hash = sha1($prefilter_query);
             // (1) create temporary table
             $db->query("SET @rank=0");
             $db->query("CREATE TEMPORARY TABLE `{$select_ids_query['temp_table']}` " . "(INDEX (`Rank`,`Document_ID`)) " . "SELECT filtered.`Document_ID`, @rank := @rank+1 AS `Rank` " . "FROM ({$prefilter_query}) AS filtered");
             // (2) check for cached offset values so we won't need to check from the beginning of the pre-filtered list
             $rank_table = $this->last_rank_table_name;
             $db->query("DELETE FROM `{$rank_table}` WHERE `Time` < NOW() - INTERVAL {$this->rank_cache_interval}");
             $cached_rank = $offset ? $db->get_row("SELECT `Offset`, `Rank` FROM `{$rank_table}`\n" . "WHERE `QueryHash` = '{$query_hash}' AND `Offset` <= {$offset}\n" . "ORDER BY `Offset` DESC\nLIMIT 1", ARRAY_A) : null;
             if ($cached_rank) {
                 $refinement_offset = $offset - $cached_rank["Offset"];
                 $refinement_rank_value = $cached_rank["Rank"];
             } else {
                 $refinement_offset = $offset;
                 $refinement_rank_value = 0;
             }
             $db->query("SET @rank_value = {$refinement_rank_value}");
             // (3) select IDs
             $db->query("{$refinement_query}\n" . "LIMIT " . ($limit + 1) . " OFFSET {$refinement_offset}");
             $ids = $db->get_col();
             $id_list = join(', ', $ids);
             if (count($ids) > $limit) {
                 // has next page
                 // total result count is set to (current page + 1 page)
                 // so there will be a paginator
                 $total_hits = $offset + 2 * $limit;
                 $total_hits_unknown = true;
                 // save rank for the next page
                 $last_rank = $db->get_var(null, 1, $limit);
                 $db->query("REPLACE INTO `{$this->last_rank_table_name}`\n                                    SET `Time` = NOW(),\n                                        `QueryHash` = '{$query_hash}',\n                                        `Offset` = " . ($offset + $limit) . ",\n                                        `Rank` = {$last_rank}");
             } else {
                 $total_hits = $offset + count($ids);
             }
         } else {
             // select IDs in a single query
             $id_list = join(', ', $db->get_col($select_ids_query));
             $total_hits = $db->last_error ? 0 : $db->get_var("SELECT FOUND_ROWS()");
         }
     } else {
         // Translator thinks there won't be any results (terms in the query are not in the index)
         // we could get $translator->get_unknown_terms(), but it is of no use for the correctors... :(
         $total_hits = 0;
     }
     // make 'result' object
     $result = new nc_search_result(array(), $total_hits);
     $result->set_query($query);
     /* @todo use $total_hits_unknown to mark that total count is not known */
     if (!$should_highlight) {
         $result->disable_highlighting();
     }
     if ($total_hits && $id_list) {
         // get field list
         $doc = new nc_search_result_document();
         $fields = $doc->get_column_names($query->get('options_to_fetch'));
         // get document data
         $doc_query = "SELECT {$fields} FROM `%t%` WHERE `Document_ID` IN ({$id_list}) " . "ORDER BY FIELD(`Document_ID`, {$id_list}) " . "LIMIT {$limit}";
         $result->select_from_database($doc_query);
     }
     return $result;
 }
Example #4
0
 /**
  * @param bool $use_temp_table
  * @return string|array
  */
 public function get_sql_query($use_temp_table)
 {
     $index = $this->index_table;
     $has_conditions = count($this->condition_stack[0]) > 0;
     $create_temp_table = $use_temp_table && $has_conditions;
     if (!$create_temp_table) {
         foreach ($this->condition_joins as $table_name => $join_condition) {
             $this->add_left_join($table_name);
         }
     }
     // prepare ORDER BY and value for the `Score` column
     $ranking_select = "1 AS `Score` ";
     $order_by = "";
     $sort_field_name = $this->query->get('sort_by');
     if ($sort_field_name == "last_modified") {
         $this->add_join($this->document_table);
         $order_by = "ORDER BY `{$this->document_table}`.`LastModified` DESC";
     } elseif ($sort_field_name) {
         // some other field
         /** @var $sort_fields nc_search_provider_index_field_manager */
         $sort_fields = $this->translator->get_fields('name', $sort_field_name)->where('is_sortable', true);
         if (count($sort_fields)) {
             $order_by = array();
             /** @var $f nc_search_provider_index_field */
             foreach ($sort_fields as $f) {
                 $field_table_name = $f->get_field_table_name();
                 $this->add_left_join($field_table_name);
                 $order_by[] = "`{$field_table_name}`.`RawData`";
             }
             $order_by = "ORDER BY IFNULL(" . join(", ", $order_by) . ", 0) " . ($this->query->get('sort_direction') == SORT_DESC ? "DESC" : "ASC");
         }
     }
     if (!$order_by) {
         // standard sorting by relevance
         $ranking_select = $this->term_ranking_calculation();
         $order_by = "ORDER BY `Score` DESC";
     }
     // Prepare area condition (will need join)
     $area_condition = "";
     $area = $this->query->get('area');
     if ($area) {
         $this->add_join($this->document_table);
         if (!$area instanceof nc_search_area) {
             $area = new nc_search_area($area);
         }
         $area_condition = "AND " . $area->get_sql_condition() . "\n";
     }
     // Compose query
     // SELECT
     $query_string = "SELECT " . ($create_temp_table ? "" : "SQL_CALC_FOUND_ROWS ") . "`{$index}`.`Document_ID`,\n" . $ranking_select;
     // FROM
     $query_string .= "FROM `{$index}` FORCE INDEX (`Content`)\n";
     // INNER JOINs
     foreach ($this->joins as $j) {
         $query_string .= "{$j}\n";
     }
     // LEFT JOINs
     foreach ($this->left_joins as $j) {
         $query_string .= "{$j}\n";
     }
     // WHERE [index_match_condition]
     // (1) Index match;                  (2) site/path filter
     $query_string .= "WHERE {$this->index_match}\n{$area_condition}";
     // (3) Extra conditions
     if ($has_conditions && !$use_temp_table) {
         $query_string .= "AND " . join("\nAND ", $this->condition_stack[0]);
     }
     // ORDER
     $query_string .= "\n{$order_by}";
     if ($use_temp_table) {
         $t = $this->get_temporary_table_name();
         $queries = array("temp_table" => $t, "prefilter" => $query_string, "refinement" => "SELECT t.`Document_ID`, t.`Rank`\n" . "FROM `{$t}` AS t\n" . join("\n", $this->condition_joins) . "\n" . "WHERE t.`Rank` >= IFNULL(@rank_value,0) AND" . join("\nAND ", $this->condition_stack[0]) . "\n" . "ORDER BY t.`Rank`\n");
         return $queries;
     } else {
         // LIMIT, OFFSET
         $query_string .= "\nLIMIT " . (int) $this->query->get('limit') . "\nOFFSET " . (int) $this->query->get('offset');
         return $query_string;
     }
 }
Example #5
0
 /**
  * Поиск по индексу
  * @param nc_search_query $query
  * @param boolean $should_highlight
  * @return nc_search_result
  */
 public function find(nc_search_query $query, $should_highlight = true)
 {
     nc_search::set_current_context(new nc_search_context(array('search_provider' => get_class($this), 'action' => 'searching', 'language' => $query->get('language'))));
     $index = $this->get_index();
     $lucene_query = $this->get_lucene_query($query);
     if ($query->get('sort_by')) {
         // custom sort
         $lucene_result = $index->find($lucene_query, $query->get('sort_by'), SORT_STRING, $query->get('sort_direction'));
     } else {
         $lucene_result = $index->find($lucene_query);
     }
     $total_hits = count($lucene_result);
     $result = new nc_search_result(array(), $total_hits);
     $result->set_query($query);
     if (!$should_highlight) {
         $result->disable_highlighting();
     }
     nc_search::set_current_context();
     // truncate to get the requested page only
     $lucene_result = array_slice($lucene_result, $query->get('offset'), $query->get('limit'));
     // сформировать nc_search_result
     $result_ids = array();
     foreach ($lucene_result as $hit) {
         $result_ids[] = $hit->doc_id;
     }
     if (count($result_ids)) {
         foreach ($result_ids as $i => $id) {
             $result_ids[$i] = (int) trim($id, "x");
         }
         $id_list = join(", ", $result_ids);
         $doc = new nc_search_result_document();
         $fields = $doc->get_column_names($query->get('options_to_fetch'));
         $query = "SELECT {$fields} FROM `%t%` WHERE `Document_ID` IN ({$id_list}) " . "ORDER BY FIELD(`Document_ID`, {$id_list})";
         $result->select_from_database($query);
     }
     return $result;
 }
Example #6
0
 /**
  *
  * @param string|nc_search_query $query
  * @param boolean $highlight_matches
  * @throws nc_search_exception
  * @return nc_search_result
  */
 public static function find($query, $highlight_matches = true)
 {
     if (self::should('EnableSearch')) {
         if (is_string($query)) {
             $query = new nc_search_query($query);
         }
         nc_search_util::set_utf_locale($query->get('language'));
         $result = self::get_provider()->find($query, $highlight_matches);
         nc_search_util::restore_locale();
         return $result;
     } else {
         throw new nc_search_exception("Search module is disabled");
     }
 }