예제 #1
0
 /**
  * Edit the search method and search index used.
  *
  * What it does:
  * - Calculates the size of the current search indexes in use.
  * - Allows to create and delete a fulltext index on the messages table.
  * - Allows to delete a custom index (that action_create() created).
  * - Called by ?action=admin;area=managesearch;sa=method.
  * - Requires the admin_forum permission.
  *
  * @uses ManageSearch template, 'select_search_method' sub-template.
  */
 public function action_edit()
 {
     global $txt, $context, $modSettings;
     // Need to work with some db search stuffs
     $db_search = db_search();
     require_once SUBSDIR . '/ManageSearch.subs.php';
     $context[$context['admin_menu_name']]['current_subsection'] = 'method';
     $context['page_title'] = $txt['search_method_title'];
     $context['sub_template'] = 'select_search_method';
     $context['supports_fulltext'] = $db_search->search_support('fulltext');
     // Load any apis.
     $context['search_apis'] = $this->loadSearchAPIs();
     // Detect whether a fulltext index is set.
     if ($context['supports_fulltext']) {
         detectFulltextIndex();
     }
     if (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'createfulltext') {
         checkSession('get');
         validateToken('admin-msm', 'get');
         $context['fulltext_index'] = 'body';
         alterFullTextIndex('{db_prefix}messages', $context['fulltext_index'], true);
     } elseif (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'removefulltext' && !empty($context['fulltext_index'])) {
         checkSession('get');
         validateToken('admin-msm', 'get');
         alterFullTextIndex('{db_prefix}messages', $context['fulltext_index']);
         $context['fulltext_index'] = '';
         // Go back to the default search method.
         if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'fulltext') {
             updateSettings(array('search_index' => ''));
         }
     } elseif (!empty($_REQUEST['sa']) && $_REQUEST['sa'] == 'removecustom') {
         checkSession('get');
         validateToken('admin-msm', 'get');
         drop_log_search_words();
         updateSettings(array('search_custom_index_config' => '', 'search_custom_index_resume' => ''));
         // Go back to the default search method.
         if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') {
             updateSettings(array('search_index' => ''));
         }
     } elseif (isset($_POST['save'])) {
         checkSession();
         validateToken('admin-msmpost');
         updateSettings(array('search_index' => empty($_POST['search_index']) || !in_array($_POST['search_index'], array('fulltext', 'custom')) && !isset($context['search_apis'][$_POST['search_index']]) ? '' : $_POST['search_index'], 'search_force_index' => isset($_POST['search_force_index']) ? '1' : '0', 'search_match_words' => isset($_POST['search_match_words']) ? '1' : '0'));
     }
     $table_info_defaults = array('data_length' => 0, 'index_length' => 0, 'fulltext_length' => 0, 'custom_index_length' => 0);
     // Get some info about the messages table, to show its size and index size.
     if (method_exists($db_search, 'membersTableInfo')) {
         $context['table_info'] = array_merge($table_info_defaults, $db_search->membersTableInfo());
     } else {
         // Here may be wolves.
         $context['table_info'] = array('data_length' => $txt['not_applicable'], 'index_length' => $txt['not_applicable'], 'fulltext_length' => $txt['not_applicable'], 'custom_index_length' => $txt['not_applicable']);
     }
     // Format the data and index length in kilobytes.
     foreach ($context['table_info'] as $type => $size) {
         // If it's not numeric then just break.  This database engine doesn't support size.
         if (!is_numeric($size)) {
             break;
         }
         $context['table_info'][$type] = comma_format($context['table_info'][$type] / 1024) . ' ' . $txt['search_method_kilobytes'];
     }
     $context['custom_index'] = !empty($modSettings['search_custom_index_config']);
     $context['partial_custom_index'] = !empty($modSettings['search_custom_index_resume']) && empty($modSettings['search_custom_index_config']);
     $context['double_index'] = !empty($context['fulltext_index']) && $context['custom_index'];
     createToken('admin-msmpost');
     createToken('admin-msm', 'get');
 }
예제 #2
0
/**
 * Creates a custom search index
 *
 * @package Search
 * @param int $start
 * @param int $messages_per_batch
 * @param string $column_size_definition
 * @param mixed[] $index_settings array containing specifics of what to create e.g. bytes per word
 */
function createSearchIndex($start, $messages_per_batch, $column_size_definition, $index_settings)
{
    global $modSettings;
    $db = database();
    $db_search = db_search();
    $step = 1;
    // Starting a new index we set up for the run
    if ($start === 0) {
        drop_log_search_words();
        $db_search->create_word_search($column_size_definition);
        // Temporarily switch back to not using a search index.
        if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') {
            updateSettings(array('search_index' => ''));
        }
        // Don't let simultaneous processes be updating the search index.
        if (!empty($modSettings['search_custom_index_config'])) {
            updateSettings(array('search_custom_index_config' => ''));
        }
    }
    $num_messages = array('done' => 0, 'todo' => 0);
    $request = $db->query('', '
		SELECT id_msg >= {int:starting_id} AS todo, COUNT(*) AS num_messages
		FROM {db_prefix}messages
		GROUP BY todo', array('starting_id' => $start));
    while ($row = $db->fetch_assoc($request)) {
        $num_messages[empty($row['todo']) ? 'done' : 'todo'] = $row['num_messages'];
    }
    // Done with indexing the messages, on to the next step
    if (empty($num_messages['todo'])) {
        $step = 2;
        $percentage = 80;
        $start = 0;
    } else {
        // Number of seconds before the next step.
        $stop = time() + 3;
        while (time() < $stop) {
            $inserts = array();
            $request = $db->query('', '
				SELECT id_msg, body
				FROM {db_prefix}messages
				WHERE id_msg BETWEEN {int:starting_id} AND {int:ending_id}
				LIMIT {int:limit}', array('starting_id' => $start, 'ending_id' => $start + $messages_per_batch - 1, 'limit' => $messages_per_batch));
            $forced_break = false;
            $number_processed = 0;
            while ($row = $db->fetch_assoc($request)) {
                // In theory it's possible for one of these to take friggin ages so add more timeout protection.
                if ($stop < time()) {
                    $forced_break = true;
                    break;
                }
                $number_processed++;
                foreach (text2words($row['body'], $index_settings['bytes_per_word'], true) as $id_word) {
                    $inserts[] = array($id_word, $row['id_msg']);
                }
            }
            $num_messages['done'] += $number_processed;
            $num_messages['todo'] -= $number_processed;
            $db->free_result($request);
            $start += $forced_break ? $number_processed : $messages_per_batch;
            if (!empty($inserts)) {
                $db->insert('ignore', '{db_prefix}log_search_words', array('id_word' => 'int', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
            }
            // Done then set up for the next step, set up for the next loop.
            if ($num_messages['todo'] === 0) {
                $step = 2;
                $start = 0;
                break;
            } else {
                updateSettings(array('search_custom_index_resume' => serialize(array_merge($index_settings, array('resume_at' => $start)))));
            }
        }
        // Since there are still steps to go, 80% is the maximum here.
        $percentage = round($num_messages['done'] / ($num_messages['done'] + $num_messages['todo']), 3) * 80;
    }
    return array($start, $step, $percentage);
}