/** * Установить свойство 'context' документа (фрагменты совпавшего с запросом текста) * (не имеет отношения к nc_search_context) */ protected function document_set_context(nc_search_result_document $doc) { // служба поиска (напр. Гугль какой-нибудь), теоретически, может установить свойство context if (!$doc->get('context') && $this->should_highlight()) { $language = $this->get_query()->get('language'); $doc->set('context', $this->highlight($doc->get('content'), $language, nc_search::get_setting('ResultContextMaxNumberOfWords'))); $doc->set('title', $this->highlight($doc->get('title'), $language, nc_search::get_setting('ResultTitleMaxNumberOfWords'))); } return $doc; }
/** * Выполнение запроса * @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; }
/** * Поиск по индексу * @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; }