Exemplo n.º 1
0
 /**
  *
  * @param nc_search_language_corrector_phrase $phrase
  * @return boolean
  */
 public function correct(nc_search_language_corrector_phrase $phrase)
 {
     // init, required
     $this->analyzer = nc_search_extension_manager::get('nc_search_language_analyzer', $this->context)->first();
     // «ПЕРВЫЙ ПОПАВШИЙСЯ»! предполагается, что анализатор вообще-то один
     $this->provider = nc_search::get_provider();
     // для начала определимся, можем ли мы что-то сделать?
     $unknown_terms = $this->get_unknown_terms($phrase);
     if (!$unknown_terms) {
         return false;
     }
     // false or empty array
     $input_count = count($unknown_terms);
     // этап 2: пробуем исправить слово
     // раскладка
     if (nc_search::should('ChangeLayoutOnEmptyResult')) {
         $unknown_terms = $this->change_keyboard_layout($unknown_terms);
     }
     // разбивка на слова
     if (nc_search::should('BreakUpWordsOnEmptyResult')) {
         $unknown_terms = $this->break_up_words($unknown_terms);
     }
     // fuzzy search
     if (nc_search::should('PerformFuzzySearchOnEmptyResult') && nc_search::should('AllowFuzzySearch')) {
         $this->add_fuzzy_search($unknown_terms);
         $everything_corrected = true;
     } else {
         $count = count($unknown_terms);
         $everything_corrected = $count == 0 || $count < $input_count && nc_search::get_setting('DefaultBooleanOperator') == 'OR';
     }
     return $everything_corrected;
 }
Exemplo n.º 2
0
 /**
  * @return nc_search_persistent_data_collection
  */
 protected static function get_all_extensions()
 {
     if (!self::$all_extensions) {
         self::$all_extensions = nc_search::load('nc_search_extension_rule', 'SELECT * FROM `%t%` WHERE `Checked` = 1 ORDER BY `Priority`');
     }
     return self::$all_extensions;
 }
Exemplo n.º 3
0
 /**
  * @return nc_search_extension_chain
  */
 protected function get_analyzers()
 {
     $index = $this->context->get('language') . "__" . $this->context->get('action');
     if (!isset(self::$analyzers[$index])) {
         self::$analyzers[$index] = nc_search_extension_manager::get('nc_search_language_analyzer', $this->context);
     }
     return self::$analyzers[$index];
 }
Exemplo n.º 4
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;
 }
Exemplo n.º 5
0
 /**
  * Перед сохранением нужно прогнать список слов через фильтры
  */
 public function save()
 {
     $mb_case = nc_search::get_setting('FilterStringCase');
     $apply_filter = !$this->get('dont_filter');
     $list = array();
     foreach ($this->get('words') as $word) {
         $word = trim($word);
         if (strlen($word)) {
             // пропустить пустые значения
             // преобразовать регистр, если в дальнейшем не будут применены фильтры
             $list[] = $apply_filter ? $word : mb_convert_case($word, $mb_case);
         }
     }
     if ($apply_filter) {
         $context = new nc_search_context(array('language' => $this->get('language')));
         $list = nc_search_extension_manager::get('nc_search_language_filter', $context)->until_first('nc_search_language_filter_synonyms')->apply('filter', $list);
     }
     if (sizeof($list) < 2) {
         throw new nc_search_data_exception(NETCAT_MODULE_SEARCH_ADMIN_SYNONYM_LIST_MUST_HAVE_AT_LEAST_TWO_WORDS);
     }
     $this->set('words', $list);
     parent::save();
 }
Exemplo n.º 6
0
 /**
  * Получить парсер для документов типа $content_type
  * @param string $content_type
  * @throws nc_search_exception
  * @return nc_search_document_parser
  */
 protected function get_parser($content_type)
 {
     if (!isset($this->parsers[$content_type])) {
         $context = new nc_search_context(array('content_type' => $content_type, 'search_provider' => nc_search::get_setting('SearchProvider')));
         $parser = nc_search_extension_manager::get('nc_search_document_parser', $context)->first();
         if (!$parser) {
             throw new nc_search_exception("Cannot get parser for the '{$content_type}'");
         }
         $this->parsers[$content_type] = $parser;
     }
     return $this->parsers[$content_type];
 }
Exemplo n.º 7
0
Arquivo: ui.php Projeto: Blu2z/implsk
 /**
  *
  * @param string $query_string
  * @param string|array $area
  * @param string $params Параметры, через амперсанд
  *   - field - поле поиска. Допустимые значения: 'title'
  *   - interval - непустое значение, если включена фильтрация по дате
  *   - intervalvalue - значение интервала
  *   - intervalunit - тип интервала (hour, day, week, month)
  *   - sortby - сортировка. Если пустое значение - сортировка по релевантности.
  *     Допустимые значения: last_updated или имя поля, по которому разрешена сортировка
  *   - sortdirection - desc (по умолчанию), asc
  *   - language - язык результатов, по умолчанию определяется автоматически
  *   - curPos - текущая позиция (номер первого результата)
  *   - recNum - количество результатов на странице, по умолчанию 10 (берется из
  *     настроек компонента в разделе)
  *   - correct - пытаться исправить запросы, не давшие результатов (по умолчанию
  *     равно соответствующей настройки модуля)
  *   - nologging - не записывать запрос в журнал запросов (при просмотре
  *     результатов из админки, чтобы не искажать картину запросов)
  * @return nc_search_data_persistent_collection
  */
 public function get_results($query_string, $area = "", $params = "")
 {
     if (!nc_search::should('EnableSearch')) {
         return new nc_search_result();
     }
     // return empty collection
     $start_time = microtime(true);
     $query_string = (string) $query_string;
     global $nc_core;
     parse_str($params, $params);
     if (isset($params["field"]) && $params["field"] && nc_search::should('AllowFieldSearch')) {
         $query_string = "{$params['field']}:({$query_string})";
     }
     $query = new nc_search_query($query_string);
     $has_interval = isset($params["interval"]) && isset($params["intervalvalue"]) && isset($params["intervalunit"]) && $params["interval"] && $params["intervalvalue"] && $params["intervalunit"];
     if ($has_interval) {
         $timestamp = strtotime("-{$params['intervalvalue']} {$params['intervalunit']}");
         $query->set('modified_after', strftime("%Y%m%d%H%M%S", $timestamp));
     }
     $allow_sort = isset($params["sortby"]) && $params["sortby"] && nc_search::should('AllowFieldSearch');
     if ($allow_sort) {
         $query->set('sort_by', $params["sortby"]);
         if (isset($params["sortdirection"]) && strtoupper($params["sortdirection"]) == 'ASC') {
             $query->set('sort_direction', SORT_ASC);
         }
     }
     if (isset($params["curPos"]) && $params["curPos"]) {
         $query->set('offset', (int) $params["curPos"]);
     }
     if (isset($params["recNum"]) && $params["recNum"]) {
         $query->set('limit', (int) $params["recNum"]);
     }
     if ($area) {
         if (is_array($area)) {
             $area = join(" ", $area);
         }
         $query->set('area', $area);
     }
     $language = isset($params["language"]) && $params["language"] ? $params["language"] : $nc_core->lang->detect_lang(1);
     $query->set('language', $language);
     $shutdown_page_path = nc_folder_path($nc_core->subdivision->get_current('Subdivision_ID'));
     register_shutdown_function('nc_search_shutdown', $shutdown_page_path, $query_string);
     $query_error = false;
     try {
         $results = nc_search::find($query);
     } catch (Exception $e) {
         $query_error = true;
         $results = new nc_search_result();
         $results->set_query($query)->set_error_message($e->getMessage());
     }
     $results->set_output_encoding(nc_core('NC_CHARSET'));
     // попробуем исправить, если не было результатов?
     $try_to_correct = $results->get_total_count() == 0 && !$query_error && (isset($params["correct"]) && $params["correct"] || nc_search::should('TryToCorrectQueries')) && preg_match_all('/[\\pL\\pN\\?\\*]+/u', $query_string, $tmp) <= nc_search::get_setting('MaxQueryLengthForCorrection');
     if ($try_to_correct) {
         $context = new nc_search_context(array("language" => $language, "action" => "searching"));
         $correctors = nc_search_extension_manager::get('nc_search_language_corrector', $context)->get_all();
         if (sizeof($correctors)) {
             $phrase = new nc_search_language_corrector_phrase($query_string);
             $rewritten_query = clone $query;
             foreach ($correctors as $corrector) {
                 if ($corrector->correct($phrase)) {
                     // что-то подправили
                     // попробуем поискать!
                     $rewritten_query->set('query_string', $phrase->to_string());
                     try {
                         $corrected_results = nc_search::find($rewritten_query);
                         if (sizeof($corrected_results)) {
                             $results = $corrected_results;
                             $results->set_correction_suggestion($phrase->get_suggestion());
                             $results->set_output_encoding(nc_core('NC_CHARSET'));
                             break;
                             // exit "foreach corrector"
                         }
                     } catch (Exception $e) {
                         // может упасть, например, если у изменённого слова есть несколько базовых форм...
                     }
                 }
                 // of "something changed"
             }
             // of "foreach corrector"
         }
         // end of "has correctors"
     }
     // end of "if ($try_to_correct)"
     $will_log = true;
     if (isset($params['nologging']) && $params['nologging'] && strlen($query_string)) {
         // только очень крутым чувакам разрешается не оставлять следов
         if (isset($GLOBALS['AUTH_USER_ID']) && isset($GLOBALS['perm']) && $GLOBALS["perm"]->isAccess(NC_PERM_MODULE)) {
             $will_log = false;
         }
     }
     if ($will_log && nc_search::should('SaveQueryHistory') && $query->get('offset') == 0) {
         $ip = ip2long($_SERVER['REMOTE_ADDR']);
         // achtung! не будет работать с IPv6!
         if ($ip > 0x7fffffff) {
             $ip -= 0x100000000;
         }
         // produce a signed 4-byte integer on 64-bit systems
         $query->set('results_count', $results->get_total_count())->set('user_ip', $ip)->set('user_id', $GLOBALS['AUTH_USER_ID'])->set('site_id', $GLOBALS['catalogue'])->save();
     }
     $results->set_search_time(microtime(true) - $start_time);
     return $results;
 }
Exemplo n.º 8
0
 /**
  * @param $doc_id
  * @param nc_search_field $field
  * @param nc_search_context $doc_context
  * @return string
  */
 protected function store_field($doc_id, nc_search_field $field, nc_search_context $doc_context)
 {
     $text = $field->get('value');
     if (strlen($text) == 0) {
         return '';
     }
     // empty fields are not stored
     $content = '';
     $raw_data = '';
     $is_stored = $field->get('is_stored') || $field->get('is_sortable');
     // 'is_indexed' → store in the `Content` field
     if ($field->get('is_indexed')) {
         $content = "";
         $filters = nc_search_extension_manager::get('nc_search_language_filter', $doc_context)->except('nc_search_language_filter_case')->stop_on(array());
         // Processing in chunks - compromise between performance (less
         // method call overhead) and memory usage
         $n = 0;
         $current_position = 0;
         $text_length = strlen($text);
         $batch_length = $this->text_batch_length;
         while ($current_position < $text_length) {
             if ($text_length < $batch_length) {
                 $batch = $text;
                 $current_position = $text_length;
             } else {
                 $space_position = strpos($text, " ", min($text_length, $current_position + $batch_length));
                 if (!$space_position) {
                     $batch = substr($text, $current_position);
                     $current_position = $text_length;
                 } else {
                     $batch = substr($text, $current_position, $space_position - $current_position);
                     $current_position = $space_position + 1;
                 }
             }
             $tokens = $this->tokenize_text(mb_convert_case($batch, nc_search::get_setting('FilterStringCase'), 'UTF-8'));
             if ($field->get('is_normalized')) {
                 // apply filters
                 $tokens = $filters->apply('filter', $tokens);
             }
             $content .= ($n ? ' ' : '') . join(' ', $this->get_term_codes($tokens, true));
             $n++;
         }
     }
     // 'is_stored' → store raw text as well
     if ($is_stored) {
         $raw_data = $text;
     }
     // save data in the DB
     $this->store_index_data($this->get_field_table_name($field), $doc_id, $content, $raw_data);
     return $content;
 }
Exemplo n.º 9
0
 /**
  *
  */
 protected function get_highlight_regexp($language)
 {
     if (!$this->highlight_regexp) {
         $query_string = $this->get_query_string();
         $context = new nc_search_context(array('language' => $language, 'action' => 'searching'));
         // Получить слова из запроса.
         // (Удалять из запроса термины с префиксом "-" и "NOT" не имеет особого смысла,
         // поскольку в результат они как правило не попадают.)
         $query_string = preg_replace("/[\\^~][\\d\\.]+/", '', $query_string);
         // операторы ^1, ~1
         preg_match_all("/[\\pL\\d\\?\\*]+/u", $query_string, $matches);
         $terms = $matches[0];
         if (strpos($query_string, "*") !== false || strpos($query_string, "?") !== false) {
             $wildcards_replacement = nc_search::should('AllowWildcardSearch') ? array("?" => ".", "*" => "[\\S]+") : array("?" => "", "*" => "");
             foreach ($terms as $i => $term) {
                 $terms[$i] = strtr($term, $wildcards_replacement);
             }
         }
         //if ( nc_Core::get_object()->NC_UNICODE ) {
         $terms = nc_search_extension_manager::get('nc_search_language_filter', $context)->except('nc_search_language_filter_stopwords')->apply('filter', $terms);
         //}
         $analyzer = nc_search_extension_manager::get('nc_search_language_analyzer', $context)->first();
         if ($analyzer) {
             $regexp = $analyzer->get_highlight_regexp($terms);
         } else {
             $regexp = nc_search_util::word_regexp("(" . join("|", $terms) . ")", "Si");
         }
         $this->highlight_regexp = $regexp;
     }
     // of "there was no 'highlight_regexp'"
     return $this->highlight_regexp;
 }
Exemplo n.º 10
0
if (count($rules)) {
    $pending_time = time() - 12 * 60 * 60;
    $pending_tasks = $db->get_var("SELECT `StartTime`\n                                     FROM `Search_Schedule`\n                                    WHERE `StartTime` < {$pending_time}\n                                    LIMIT 1");
    if ($pending_tasks) {
        $error_message = NETCAT_MODULE_SEARCH_WIDGET_CHECK_CRONTAB;
    }
} else {
    $error_message = NETCAT_MODULE_SEARCH_WIDGET_NO_RULES;
}
// Ошибки конфигурации
ob_start();
// (1) Индексатор
$provider->check_environment(true);
// (2) Парсеры
$parser_context = new nc_search_context(array('search_provider' => $provider));
$all_parsers = nc_search_extension_manager::get('nc_search_document_parser', $parser_context)->get_all();
/** @var nc_search_document_parser $parser */
foreach ($all_parsers as $parser) {
    $parser->check_environment(true);
}
$has_configuration_errors = strlen(ob_get_clean()) > 0;
if ($has_configuration_errors) {
    $error_message = NETCAT_MODULE_SEARCH_WIDGET_CONFIGURATION_ERRORS;
}
// -----------------------------------------------------------------------------
$full_link = $nc_core->SUB_FOLDER . $nc_core->HTTP_ROOT_PATH . 'modules/search/admin.php?view=info';
$full_link_brokenlinks = $nc_core->SUB_FOLDER . $nc_core->HTTP_ROOT_PATH . 'modules/search/admin.php?view=brokenlinks';
?>

<table class="nc-widget-grid">
    <col width="50%" />
Exemplo n.º 11
0
 * одну из базовых форм
 */
if (!class_exists("nc_system")) {
    die;
}
$ui = $this->get_ui();
$ui->add_lists_toolbar();
$ui->add_submit_button(NETCAT_MODULE_SEARCH_ADMIN_SAVE);
$ui->add_back_button();
$stopword = $this->data_form('nc_search_language_stopword', 'stopwords');
$stopword->set_values($this->get_input('data'), true);
$word = $stopword->get('word');
$lang = $stopword->get('language');
$input = (array) $word;
$context = new nc_search_context(array('language' => $lang));
$filtered = nc_search_extension_manager::get('nc_search_language_filter', $context)->until_first('nc_search_language_filter_stopwords')->apply('filter', (array) $input);
if ($filtered == $input) {
    // на входе базовая форма — OK!
    $params = array('view' => 'stopwords', 'action' => 'save', 'data_class' => 'nc_search_language_stopword', 'id' => $stopword->get_id(), 'data' => array('language' => $stopword->get('language'), 'word' => $word));
    // !! на входе в cp-1251 всегда кодировка windows-1251, но сейчас в $params - в utf-8
    if (!$nc_core->NC_UNICODE) {
        $params = $nc_core->utf8->array_utf2win($params);
    }
    $this->redirect("?" . http_build_query($params, null, '&'));
}
echo "<fieldset><legend>", NETCAT_MODULE_SEARCH_ADMIN_STOPWORD, "</legend><div class='stopword_variants'>";
$num_variants = sizeof($filtered);
if ($num_variants == 0) {
    printf(NETCAT_MODULE_SEARCH_ADMIN_STOPWORD_HAS_NO_BASEFORM, $word);
    print $this->hidden('data[word]', $word);
} elseif ($num_variants == 1) {
Exemplo n.º 12
0
 /**
  * Фильтры сделаны нестандартным для Lucene способом; оправдания следующие:
  *   - возможно, в будущем в модуле будет свой парсер, и он будет обрабатывать
  *     ситуации с синонимами и проч. переписыванием запросов, e.g.:
  *     (word1 word2) → (word1 word2 syn2); "word1 word2" → ("word1 word2" OR "word1 syn2")
  *   - чтобы сделать через addFilter(), нужно создать дублирующие классы или класс-прокси
  *     (или отказаться от идеи возможного использования фильтров netcat с
  *     другими поставщиками поиска, которые [*может быть*] будут)
  *   - стандартные фильтры создают множество временных объектов
  *     (каждый фильтр, если он что-то сделал, создает новый токен)
  *
  * @param string $term
  * @return array может содержать 0 (стоп-слова), 1 или несколько (синонимы) элементов
  *
  */
 protected function apply_nc_filters($term)
 {
     $context = nc_search::get_current_context();
     return nc_search_extension_manager::get('nc_search_language_filter', $context)->stop_on(array())->apply('filter', array($term));
 }