Perforce Chronicle 2012.2/486814
API Documentation
|
Manages the search and index. More...
Public Member Functions | |
indexAction () | |
Show a manage search page. | |
optimizeAction () | |
optimize the Lucene search index. | |
rebuildAction () | |
Rebuild the Lucene search index. | |
statusAction () | |
Provide a status update in Json format. | |
Public Attributes | |
$contexts | |
const | REBUILD_BATCH_SIZE = 100 |
Protected Member Functions | |
_removeSearchIndex ($indexName) | |
Remove the search index by deleting all files from its folder on disk. | |
_setActiveSearchIndex ($index) | |
Make a search index active. | |
Static Protected Member Functions | |
static | _nomaliseIndexName ($index) |
Normalise a Lucene search index name. | |
Protected Attributes | |
$_activeIndexPath = 'search-index' | |
$_maintenanceLockFile = 'search.maintenance.lock.file' | |
$_maintenanceStatusFile = 'search.maintenance.status.file' | |
$_statusFile = null |
Manages the search and index.
static Search_ManageController::_nomaliseIndexName | ( | $ | index | ) | [static, protected] |
Normalise a Lucene search index name.
string | $index | the original index name |
{ // if the name is not a string if (!is_string($index)) { return ''; } // trim spaces and slashes $index = trim($index, " \t\n\r\0\x0B/\\"); return $index; }
Search_ManageController::_removeSearchIndex | ( | $ | indexName | ) | [protected] |
Remove the search index by deleting all files from its folder on disk.
string | $indexName | the folder name of a search index |
{ // if the index folder is an empty string, nothing to do if (strlen($indexName) == 0) { return true; } $indexDirectory = P4Cms_Site::fetchActive()->getDataPath() . '/' . $indexName; // if the index does not exist, nothing to do if (!file_exists($indexDirectory)) { return true; } $files = scandir($indexDirectory); // remove all files in the search index folder foreach ($files as $file) { if (is_dir($file)) { continue; } unlink($indexDirectory . '/' . $file); } return rmdir($indexDirectory); }
Search_ManageController::_setActiveSearchIndex | ( | $ | index | ) | [protected] |
Make a search index active.
string | $index | the search index directory |
{ // if $index is not a string or it's an empty string // we cannot get search index $index = $this->_nomaliseIndexName($index); if (strlen($index) == 0) { throw new Zend_Search_Exception( 'Require a folder name to set the active Search index.' ); } $activeIndex = $this->_activeIndexPath; // nothing to do if the index given is the active index if ($index == $activeIndex) { return true; } // remove the active index contents if (!$this->_removeSearchIndex($activeIndex)) { throw new Zend_Search_Exception( "Failed removing the active search index: $activeIndex." ); } $dataPath = P4Cms_Site::fetchActive()->getDataPath() . '/'; $newPath = $dataPath . $index; $activePath = $dataPath . $activeIndex; return rename($newPath, $activePath); }
Search_ManageController::indexAction | ( | ) |
Show a manage search page.
{ // enforce permissions. $this->acl->check('search', 'manage'); $request = $this->getRequest(); // get the search form. $form = new Search_Form_Manage; if ($request->isPost()) { $data = $request->getPost(); if ( $form->isValid($data)) { $maxBufferedDocs = $data['maxBufferedDocs']; $maxMergeDocs = $data['maxMergeDocs']; $mergeFactor = $data['mergeFactor']; $config = array(); if (strlen($maxBufferedDocs) != 0) { $config['maxBufferedDocs'] = $maxBufferedDocs; } else { $config['maxBufferedDocs'] = Search_Module::getMaxBufferedDocs(); } if (strlen($maxMergeDocs) != 0) { $config['maxMergeDocs'] = $maxMergeDocs; } else { $config['maxMergeDocs'] = Search_Module::getMaxMergeDocs(); } if (strlen($mergeFactor) != 0) { $config['mergeFactor'] = $mergeFactor; } else { $config['mergeFactor'] = Search_Module::getMergeFactor(); } $this->_saveConfig($config); P4Cms_Notifications::add( 'Search configuration saved.', P4Cms_Notifications::SEVERITY_SUCCESS ); $this->redirector->gotoSimple('index'); } } else { $data = array(); $data['maxBufferedDocs'] = Search_Module::getMaxBufferedDocs(); $data['maxMergeDocs'] = (Search_Module::getMaxMergeDocs() && (Search_Module::getMaxMergeDocs() != PHP_INT_MAX)) ? Search_Module::getMaxMergeDocs() : ''; $data['mergeFactor'] = Search_Module::getMergeFactor(); $form->populate($data); } $this->view->form = $form; $this->getHelper('layout')->setLayout('manage-layout'); $this->view->headTitle()->set('Manage Search'); }
Search_ManageController::optimizeAction | ( | ) |
optimize the Lucene search index.
{ // enforce permissions. $this->acl->check('search', 'manage'); // check if there is another maintenance task (optimize/rebuild) // running. if it is, redirect to the status page $maitenanceLockFile = P4Cms_Site::fetchActive()->getDataPath() . '/' . $this->_maintenanceLockFile; if (file_exists($maitenanceLockFile)) { $redirector = $this->_helper->getHelper('redirector'); $redirector->gotoSimple('status'); return; } // create the maintenance lock file touch($maitenanceLockFile); P4Cms_Log::log( "optimize Search Index: BEGIN; pid=". getmypid(), P4Cms_Log::DEBUG ); // put the current task in the session $_SESSION['searchMaintenanceTask'] = 'optimize'; $this->_writeStatusFile( array( 'action' => 'optimize', 'label' => 'optimizing search index', 'message' => 'Start optimizing search index.', 'time' => time(), 'done' => false, ) ); // close the session but continue running, since index rebuilt may // take longer than browser timeout $this->getHelper('browserDisconnect')->disconnect('status', 10); $index = Search_Module::factory(); $index->optimize(); $this->_writeStatusFile( array( 'action' => 'optimize', 'label' => 'optimizing search index', 'message' => 'Done. Search index optimization completed.', 'time' => time(), 'done' => true, ) ); unlink($maitenanceLockFile); }
Search_ManageController::rebuildAction | ( | ) |
Rebuild the Lucene search index.
p4cms.search.index.rebuild Return a Zend_Paginator of P4Cms_Content entries (or null) to be included when the search index is rebuilt.
{ // enforce permissions. $this->acl->check('search', 'manage'); // check if there is another maintenance task (optimize/rebuild) // running. if it is, redirect to the status page $maitenanceLockFile = P4Cms_Site::fetchActive()->getDataPath() . '/' . $this->_maintenanceLockFile; if (file_exists($maitenanceLockFile)) { $redirector = $this->_helper->getHelper('redirector'); $redirector->gotoSimple('status'); return; } // create the maintenance lock file touch($maitenanceLockFile); P4Cms_Log::log( "Rebuild Search Index: BEGIN; pid=". getmypid(), P4Cms_Log::DEBUG ); // put the current task in the session $_SESSION['searchMaintenanceTask'] = 'rebuild'; // put the status file's filename in the session $this->_statusFile = tempnam('/tmp', 'p4cms-search-rebuild.'. getmypid() .'.'); $_SESSION['searchMaintenanceStatusFile'] = $this->_statusFile; $this->_writeStatusFile( array( 'action' => 'rebuild', 'label' => 'rebuilding search index', 'message' => 'Start rebuilding search index.', 'time' => time(), 'done' => false, ) ); // close the session but continue running, since index rebuilt may // take longer than browser timeout $this->getHelper('browserDisconnect')->disconnect('status', 60 * 24); // clear the current index, if any // and create a new one $index = Search_Module::factory('temp-index'); // publish the search index rebuild topic, expects subscribers to // return Zend_Paginator instances $feedbacks = P4Cms_PubSub::publish('p4cms.search.index.rebuild'); $entryCount = 0; // get the total number of content entries foreach ($feedbacks as $feedback) { if ($feedback instanceof Zend_Paginator) { $entryCount += $feedback->getTotalItemCount(); } } // start to rebuild the search index $count = 0; foreach ($feedbacks as $feedback) { // if the feedback is not a paginator as expected, skip it if (!$feedback instanceof Zend_Paginator) { continue; } $feedback->setItemCountPerPage(self::REBUILD_BATCH_SIZE); // for each page, get the items and index them for ($i = 1; $i <= $feedback->count(); $i++) { // set the current page $feedback->setCurrentPageNumber($i); // if there is no items in the current page, nothing to do if ($feedback->getCurrentItemCount() == 0) { continue; } $itemCountPerPage = $feedback->getCurrentItemCount(); // get a batch of entries $this->_writeStatusFile( array( 'action' => 'rebuild', 'label' => 'fetching entries', 'message' => "Fetching the $i batch of $entryCount existing entries...", 'time' => time(), 'done' => false, ) ); // get the items in the current page $items = $feedback->getCurrentItems(); // update the status $this->_writeStatusFile( array( 'action' => 'rebuild', 'label' => 'rebuilding', 'message' => "Start rebuilding from the $i batch of $entryCount existing entries.", 'time' => time(), 'done' => false, ) ); foreach ($items as $item) { if (!$item instanceof Zend_Search_Lucene_Document) { if (method_exists($item, 'toLuceneDocument')) { try { $item = $item->toLuceneDocument(); } catch (Zend_Filter_Exception $e) { P4Cms_Log::logException( 'Failed converting content to Lucene document.', $e ); continue; } catch (Zend_Search_Lucene_Exception $e) { P4Cms_Log::logException( 'Failed converting content to Lucene document.', $e ); continue; } } else { continue; } } $index->addDocument($item); $count++; // update the status $this->_writeStatusFile( array( 'action' => 'rebuild', 'label' => 'indexing content', 'message' => "Indexing content no. $count of $entryCount.", 'count' => $count, 'total' => $entryCount, 'time' => time(), 'done' => false, ) ); } } } // optimize the index after it's rebuilt $this->_writeStatusFile( array( 'action' => 'optimize', 'label' => 'optimizing search index', 'index' => 'temp-index', 'message' => 'Optimizing the search index after rebuild...', 'time' => time(), 'done' => false, ) ); $index->optimize(); $this->_writeStatusFile( array( 'action' => 'optimize', 'label' => 'optimizing search index', 'index' => 'temp-index', 'message' => "Done. Search Index has been rebuilt.", 'time' => time(), 'done' => true ) ); Search_Module::clearSearchInstances(); $this->_setActiveSearchIndex('temp-index'); unlink($maitenanceLockFile); }
Search_ManageController::statusAction | ( | ) |
Provide a status update in Json format.
{ // enforce permissions. $this->acl->check('search', 'manage'); $statusFile = P4Cms_Site::fetchActive()->getDataPath() . '/' . $this->_maintenanceStatusFile; if (!file_exists($statusFile) ) { $status = array( 'message' => 'Search Index maintenance task completed', 'done' => true ); $this->view->status = $status; return; } $status = $this->_readStatusFile(); // for optimize, get the progress and merge it to the status file contents if (isset($status['action']) && ($status['action'] == 'optimize') && !$status['done']) { if (isset($status['index'])) { $status = array_merge( $status, $this->_getoptimizeProgress($status['index']) ); } else { $status = array_merge($status, $this->_getoptimizeProgress()); } } if (!array_key_exists('searchMaintenanceTask', $_SESSION)) { $status['message'] = "A Search Index '" . ucfirst($status['action']) . "' operation is currently running. Its status and progress is below -- " . $status['message']; } $this->contextSwitch->initContext('json'); $this->view->status = $status; }
Search_ManageController::$_activeIndexPath = 'search-index' [protected] |
Search_ManageController::$_maintenanceLockFile = 'search.maintenance.lock.file' [protected] |
Search_ManageController::$_maintenanceStatusFile = 'search.maintenance.status.file' [protected] |
Search_ManageController::$_statusFile = null [protected] |
Search_ManageController::$contexts |
array( 'status' => array('json' => array('POST', 'GET')) )
const Search_ManageController::REBUILD_BATCH_SIZE = 100 |