Big global search update for 1.9. Will resolve major bug points in Global Search component section.

This commit is contained in:
diml
2008-12-17 20:52:07 +00:00
parent 323a68467c
commit b56ccc3192
92 changed files with 4297 additions and 1432 deletions
+1 -1
View File
@@ -36,7 +36,7 @@
global $CFG;
if (empty($CFG->enableglobalsearch)) {
return '';
return get_string('disabledsearch', 'search');
}
//cache block contents
+196 -13
View File
@@ -1,5 +1,22 @@
<?php
/**
* Requires and includes
*/
include_once $CFG->dirroot."/search/lib.php";
$defaultfiletypes = "PDF,TXT,HTML,PPT,XML,DOC,HTM";
if (!isset($CFG->block_search_utf8dir)){
$CFG->block_search_utf8dir = 0;
}
if (!isset($CFG->block_search_softlock)){
$CFG->block_search_softlock = 0;
}
?>
<div style="text-align:center;">
<table cellspacing="5">
<table cellspacing="5" width="90%">
<tr>
<td valign="top" align="right">
<b><?php print_string('configsearchtext', 'block_search') ?>:</b>
@@ -26,6 +43,26 @@
} ?>"/><br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('configutf8transcoding', 'block_search') ?>:</b>
</td>
<td valign="top" align="left">
<input type="radio" name="block_search_utf8dir" value="0" <?php if (!$CFG->block_search_utf8dir) echo "checked=\"checked\"" ?> /> <?php print_string('enabled', 'block_search') ?>
<input type="radio" name="block_search_utf8dir" value="1" <?php if ($CFG->block_search_utf8dir) echo "checked=\"checked\"" ?> /> <?php print_string('disabled', 'block_search') ?>
<br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('configusingsoftlock', 'block_search') ?>:</b>
</td>
<td valign="top" align="left">
<input type="radio" name="block_search_softlock" value="0" <?php if (!$CFG->block_search_softlock) echo "checked=\"checked\"" ?> /> <?php print_string('disabled', 'block_search') ?>
<input type="radio" name="block_search_softlock" value="1" <?php if ($CFG->block_search_softlock) echo "checked=\"checked\"" ?> /> <?php print_string('enabled', 'block_search') ?>
<br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('configenablefileindexing', 'block_search') ?>:</b>
@@ -48,11 +85,12 @@
</td>
<td valign="top" align="left">
<input id="block_search_filetypes" type="text" name="block_search_filetypes" value="<?php
if(isset($CFG->block_search_filetypes)) {
p($CFG->block_search_filetypes);
} else {
p("PDF,TXT,HTML,PPT,XML,DOC,HTM");
} ?>"/><br/><br/>
if(!isset($CFG->block_search_filetypes)) {
$CFG->block_search_filetypes = $defaultfiletypes;
}
p($CFG->block_search_filetypes);
?>" />
<br/><br/>
</td>
</tr>
<tr>
@@ -69,6 +107,24 @@
<br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('configlimitindexbody', 'block_search') ?>:</b>
</td>
<td valign="top" align="left">
<input id="block_search_limit_index_body" type="text" size="8" name="block_search_limit_index_body" value="<?php
if(isset($CFG->block_search_limit_index_body)) {
p($CFG->block_search_limit_index_body);
} else {
p('');
} ?>"/> <?php print_string('bytes', 'block_search') ?><br/><br/>
</td>
</tr>
</table>
<fieldset name="">
<legend align="top"><?php print_string('pdfhandling', 'block_search') ?></legend>
<table cellspacing="5" width="90%">
<tr>
<td valign="top" align="right">
<b><?php print_string('configpdftotextcmd', 'block_search') ?>:</b>
@@ -88,6 +144,12 @@
} ?>"/><br/><br/>
</td>
</tr>
</table>
</fieldset>
<fieldset name="">
<legend align="top"><?php print_string('wordhandling', 'block_search') ?></legend>
<table cellspacing="5" width="90%">
<tr>
<td valign="top" align="right">
<b><?php print_string('configwordtotextcmd', 'block_search') ?>:</b>
@@ -124,19 +186,140 @@
} ?>"/><br/><br/>
</td>
</tr>
</table>
</fieldset>
<?php
$types = split(',', $CFG->block_search_filetypes);
if (!empty($types)){
foreach($types as $type) {
$utype = strtoupper($type);
$type = strtolower($type);
$type = trim($type);
if (preg_match("/\\b$type\\b/i", $defaultfiletypes)) continue;
?>
<fieldset name="">
<legend align="top"><?php echo get_string('handlingfor', 'block_search').' '.$utype ?></legend>
<table cellspacing="5" width="90%">
<tr>
<td valign="top" align="right">
<b><?php print_string('configlimitindexbody', 'block_search') ?>:</b>
<b><?php print_string('configtypetotxtcmd', 'block_search') ?>:</b>
</td>
<td valign="top" align="left">
<input id="block_search_limit_index_body" type="text" size="8" name="block_search_limit_index_body" value="<?php
if(isset($CFG->block_search_limit_index_body)) {
p($CFG->block_search_limit_index_body);
} else {
p('');
} ?>"/> <?php print_string('bytes', 'block_search') ?><br/><br/>
<input id="block_search_<?php p($type) ?>_to_text_cmd" type="text" size="60" name="block_search_<?php p($type) ?>_to_text_cmd" value="<?php
$propname = "block_search_{$type}_to_text_cmd";
if(isset($CFG->$propname)) {
p($CFG->$propname);
}
?>"/>
<br/><br/>
</td>
</tr>
<tr>
<td valign="top" align="right">
<b><?php print_string('configtypetotxtenv', 'block_search') ?>:</b>
</td>
<td valign="top" align="left">
<input id="block_search_<?php p($type) ?>_to_text_env" type="text" size="60" name="block_search_<?php p($type) ?>_to_text_env" value="<?php
$propname = "block_search_{$type}_to_text_env";
if(isset($CFG->$propname)) {
echo stripslashes($CFG->$propname);
} ?>"/><br/><br/>
</td>
</tr>
</table>
</fieldset>
<?php
}
}
?>
<fieldset name="">
<legend align="top"><?php echo get_string('searchdiscovery', 'block_search') ?></legend>
<table>
<tr>
<td>
<pre>
<?php
$searchnames = search_collect_searchables(true);
$searchable_list = implode("','", $searchnames);
?>
</pre>
</td>
</tr>
</table>
</fieldset>
<fieldset name="">
<legend align="top"><?php echo get_string('modulessearchswitches', 'block_search') ?></legend>
<table cellspacing="5" width="90%">
<tr valign="top">
<td align="left">
<?php
$i = 0;
$found_searchable_modules = 0;
if ($modules = get_records_select('modules', " name IN ('{$searchable_list}') ", 'name', 'id,name')){
foreach($modules as $module){
$i++;
$keyname = "search_in_{$module->name}";
$checkedup = (!isset($CFG->$keyname) || $CFG->$keyname) ? 'checked="checked"' : '' ;
$checkeddown = !(!isset($CFG->$keyname) || $CFG->$keyname) ? 'checked="checked"' : '' ;
echo "<input type=\"radio\" name=\"search_in_{$module->name}\" value=\"0\" {$checkeddown} /> " . get_string('no');
echo " - <input type=\"radio\" name=\"search_in_{$module->name}\" value=\"1\" {$checkedup} /> " . get_string('yes');
echo " - ".get_string('modulename', $module->name).'<br/>';
if ($i % 20 == 0){
echo "</td><td align=\"left\">";
}
$found_searchable_modules = 1;
}
}
if (!$found_searchable_modules) {
print_string('nosearchablemodules', 'block_search');
}
?>
</td>
</tr>
</table>
</fieldset>
<fieldset name="">
<legend align="top"><?php echo get_string('blockssearchswitches', 'block_search') ?></legend>
<table cellspacing="5" width="90%">
<tr valign="top">
<td align="left">
<?php
$i = 0;
$found_searchable_blocks = 0;
if ($blocks = get_records_select('block', " name IN ('{$searchable_list}') ", 'name', 'id,name')){
foreach($blocks as $block){
$i++;
$keyname = "search_in_{$block->name}";
$checked = (!isset($CFG->$keyname) || $CFG->$keyname) ? 'checked="checked"' : '' ;
echo "<input type=\"checkbox\" name=\"search_in_{$block->name}\" value=\"1\" {$checked} />";
// multiple fallback strategy to get the name of the block
$blocklabel = get_string('blockname', 'block_'.$block->name);
if ($blocklabel == '[[blockname]]') $blocklabel = get_string($block->name, 'block_'.$block->name);
if ($blocklabel == "[[{$block->name}]]") $blocklabel = "<span class=\"dimmed_text\">$block->name</span>";
echo " - ".$blocklabel.'<br/>';
if ($i % 20 == 0){
echo "</td><td align=\"left\">";
}
$found_searchable_blocks = 1;
}
}
if (!$found_searchable_blocks) {
print_string('nosearchableblocks', 'block_search');
}
?>
</td>
</tr>
</table>
</fieldset>
<table cellspacing="5" width="90%">
<tr>
<td valign="top" align="right" colspan="2">
<input type="submit" value="<?php print_string('savechanges'); ?>" />
+21 -2
View File
@@ -1,15 +1,34 @@
<?php
$string['asynchronous'] = 'Asynchronous (Ajax)';
$string['blockname'] = 'Global Search';
$string['blockssearchswitches'] = 'Indexer activation for blocks';
$string['blockssearchmnetfeatures'] = 'Moodle Network Search';
$string['bytes'] = ' bytes (0 stands for no limits)';
$string['configbuttonlabel'] = 'Button label';
$string['configenablefileindexing'] = 'Enable file indexing';
$string['configfiletypes'] = 'File types handled';
$string['configlimitindexbody'] = 'Indexed body size limitation';
$string['configpdftotextcmd'] = 'Path to command pdftotext';
$string['configsearchtext'] = 'Search text';
$string['configtypetotxtcmd'] = 'Converter\'s command line';
$string['configtypetotxtenv'] = 'Environment define for converter';
$string['configusingsoftlock'] = 'Software interlocking (for NFS mounted clusters)';
$string['configutf8transcoding'] = 'UTF8 transcoding direction of results';
$string['configwordtotextcmd'] = 'Path to command doctotext';
$string['configwordtotextenv'] = 'Environment setting for the MSWord converter';
$string['configsearchtext'] = 'Search text';
$string['disabled'] = 'Disabled';
$string['disabledsearch'] = 'The global search engine is off. Inform your administrator.';
$string['enabled'] = 'Enabled';
$string['go'] = 'Go!';
$string['bytes'] = ' bytes (0 stands for no limits)';
$string['handlingfor'] = 'Extra handling for';
$string['modulessearchswitches'] = 'Indexer activation for modules';
$string['nosearchableblocks'] = 'No searchable blocks';
$string['nosearchablemodules'] = 'No searchable modules';
$string['pdfhandling'] = 'Acrobat PDF handling';
$string['search'] = 'Search';
$string['searchdiscovery'] = 'Searchable items discovery';
$string['searchmoodle'] = 'Search Moodle';
$string['synchronous'] = 'Synchronous';
$string['usemoodleroot'] = 'Use moodle root for external converters';
$string['wordhandling'] = 'Microsoft Word handling';
?>
+3 -3
View File
@@ -14,7 +14,7 @@
*
* @category Zend
* @package Zend_Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -22,13 +22,13 @@
/**
* Framework base exception
*/
require_once $CFG->dirroot.'/search/Zend/Exception.php';
require_once "Zend/Exception.php";
/**
* @category Zend
* @package Zend_Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Exception extends Zend_Exception
+426 -77
View File
@@ -14,65 +14,72 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once "Zend/Search/Lucene/Exception.php";
/** Zend_Search_Lucene_Document */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Document.php';
require_once "Zend/Search/Lucene/Document.php";
/** Zend_Search_Lucene_Document_Html */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Document/Html.php';
require_once "Zend/Search/Lucene/Document/Html.php";
/** Zend_Search_Lucene_Storage_Directory */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/Directory/Filesystem.php';
/** Zend_Search_Lucene_Storage_Directory_Filesystem */
require_once "Zend/Search/Lucene/Storage/Directory/Filesystem.php";
/** Zend_Search_Lucene_Storage_File_Memory */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/File/Memory.php';
require_once "Zend/Search/Lucene/Storage/File/Memory.php";
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once "Zend/Search/Lucene/Index/Term.php";
/** Zend_Search_Lucene_Index_TermInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/TermInfo.php';
require_once "Zend/Search/Lucene/Index/TermInfo.php";
/** Zend_Search_Lucene_Index_SegmentInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfo.php';
require_once "Zend/Search/Lucene/Index/SegmentInfo.php";
/** Zend_Search_Lucene_Index_FieldInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/FieldInfo.php';
require_once "Zend/Search/Lucene/Index/FieldInfo.php";
/** Zend_Search_Lucene_Index_Writer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Writer.php';
require_once "Zend/Search/Lucene/Index/Writer.php";
/** Zend_Search_Lucene_Search_QueryParser */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParser.php';
require_once "Zend/Search/Lucene/Search/QueryParser.php";
/** Zend_Search_Lucene_Search_QueryHit */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryHit.php';
require_once "Zend/Search/Lucene/Search/QueryHit.php";
/** Zend_Search_Lucene_Search_Similarity */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Similarity.php';
require_once "Zend/Search/Lucene/Search/Similarity.php";
/** Zend_Search_Lucene_Index_SegmentInfoPriorityQueue */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php';
require_once "Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php";
/** Zend_Search_Lucene_LockManager */
if (@$CFG->block_search_softlock){
require_once "Zend/Search/Lucene/SoftLockManager.php";
} else {
require_once "Zend/Search/Lucene/LockManager.php";
}
/** Zend_Search_Lucene_Interface */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Interface.php';
require_once "Zend/Search/Lucene/Interface.php";
/** Zend_Search_Lucene_Proxy */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Proxy.php';
require_once "Zend/Search/Lucene/Proxy.php";
/**
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
@@ -86,6 +93,15 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
*/
private static $_defaultSearchField = null;
/**
* Result set limit
*
* 0 means no limit
*
* @var integer
*/
private static $_resultSetLimit = 0;
/**
* File system adapter.
*
@@ -129,13 +145,6 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
private $_hasChanges = false;
/**
* Index lock object
*
* @var Zend_Search_Lucene_Storage_File
*/
private $_lock;
/**
* Signal, that index is already closed, changes are fixed and resources are cleaned up
*
@@ -150,7 +159,14 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
*/
private $_refCount = 0;
/**
* Current segment generation
*
* @var integer
*/
private $_generation;
/**
* Create index
*
@@ -173,56 +189,101 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
return new Zend_Search_Lucene_Proxy(new Zend_Search_Lucene($directory, false));
}
/** Generation retrieving counter */
const GENERATION_RETRIEVE_COUNT = 10;
/** Pause between generation retrieving attempts in milliseconds */
const GENERATION_RETRIEVE_PAUSE = 50;
/**
* Opens the index.
* Get current generation number
*
* IndexReader constructor needs Directory as a parameter. It should be
* a string with a path to the index folder or a Directory object.
* Returns generation number
* 0 means pre-2.1 index format
* -1 means there are no segments files.
*
* @param mixed $directory
* @param Zend_Search_Lucene_Storage_Directory $directory
* @return integer
* @throws Zend_Search_Lucene_Exception
*/
public function __construct($directory = null, $create = false)
public static function getActualGeneration(Zend_Search_Lucene_Storage_Directory $directory)
{
if ($directory === null) {
throw new Zend_Search_Exception('No index directory specified');
}
/**
* Zend_Search_Lucene uses segments.gen file to retrieve current generation number
*
* Apache Lucene index format documentation mentions this method only as a fallback method
*
* Nevertheless we use it according to the performance considerations
*
* @todo check if we can use some modification of Apache Lucene generation determination algorithm
* without performance problems
*/
if ($directory instanceof Zend_Search_Lucene_Storage_Directory_Filesystem) {
$this->_directory = $directory;
$this->_closeDirOnExit = false;
} else {
$this->_directory = new Zend_Search_Lucene_Storage_Directory_Filesystem($directory);
$this->_closeDirOnExit = true;
}
try {
for ($count = 0; $count < self::GENERATION_RETRIEVE_COUNT; $count++) {
// Try to get generation file
$genFile = $directory->getFileObject('segments.gen', false);
$format = $genFile->readInt();
if ($format != (int)0xFFFFFFFE) {
throw new Zend_Search_Lucene_Exception('Wrong segments.gen file format');
}
// Get a shared lock to the index
$this->_lock = $this->_directory->createFile('index.lock');
$gen1 = $genFile->readLong();
$gen2 = $genFile->readLong();
$this->_segmentInfos = array();
if ($gen1 == $gen2) {
return $gen1;
}
if ($create) {
// Throw an exception if index is under processing now
if (!$this->_lock->lock(LOCK_EX, true)) {
throw new Zend_Search_Lucene_Exception('Can\'t create index. It\'s under processing now');
usleep(self::GENERATION_RETRIEVE_PAUSE * 1000);
}
// Writer will create segments file for empty segments list
$this->_writer = new Zend_Search_Lucene_Index_Writer($this->_directory, $this->_segmentInfos, true);
// All passes are failed
throw new Zend_Search_Lucene_Exception('Index is under processing now');
} catch (Zend_Search_Lucene_Exception $e) {
if (strpos($e->getMessage(), 'is not readable') !== false) {
try {
// Try to open old style segments file
$segmentsFile = $directory->getFileObject('segments', false);
if (!$this->_lock->lock(LOCK_SH)) {
throw new Zend_Search_Lucene_Exception('Can\'t reduce lock level from Exclusive to Shared');
// It's pre-2.1 index
return 0;
} catch (Zend_Search_Lucene_Exception $e) {
if (strpos($e->getMessage(), 'is not readable') !== false) {
return -1;
} else {
throw $e;
}
}
} else {
throw $e;
}
} else {
// Wait if index is under switching from one set of segments to another (Index_Writer::_updateSegments())
if (!$this->_lock->lock(LOCK_SH)) {
throw new Zend_Search_Lucene_Exception('Can\'t obtain shared index lock');
}
$this->_writer = null;
}
return -1;
}
/**
* Get segments file name
*
* @param integer $generation
* @return string
*/
public static function getSegmentFileName($generation)
{
if ($generation == 0) {
return 'segments';
}
return 'segments_' . base_convert($generation, 10, 36);
}
/**
* Read segments file for pre-2.1 Lucene index format
*/
private function _readPre21SegmentsFile()
{
$segmentsFile = $this->_directory->getFileObject('segments');
$format = $segmentsFile->readInt();
@@ -248,13 +309,156 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
$segSize = $segmentsFile->readInt();
$this->_docCount += $segSize;
$this->_segmentInfos[] =
new Zend_Search_Lucene_Index_SegmentInfo($segName,
$segSize,
$this->_directory);
$this->_segmentInfos[$segName] =
new Zend_Search_Lucene_Index_SegmentInfo($this->_directory,
$segName,
$segSize);
}
}
/**
* Read segments file
*
* @throws Zend_Search_Lucene_Exception
*/
private function _readSegmentsFile()
{
$segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation));
$format = $segmentsFile->readInt();
if ($format != (int)0xFFFFFFFD) {
throw new Zend_Search_Lucene_Exception('Wrong segments file format');
}
// read version
// $segmentsFile->readLong();
$segmentsFile->readInt(); $segmentsFile->readInt();
// read segment name counter
$segmentsFile->readInt();
$segments = $segmentsFile->readInt();
$this->_docCount = 0;
// read segmentInfos
for ($count = 0; $count < $segments; $count++) {
$segName = $segmentsFile->readString();
$segSize = $segmentsFile->readInt();
// 2.1+ specific properties
//$delGen = $segmentsFile->readLong();
$delGenHigh = $segmentsFile->readInt();
$delGenLow = $segmentsFile->readInt();
if ($delGenHigh == (int)0xFFFFFFFF && $delGenLow == (int)0xFFFFFFFF) {
$delGen = -1; // There are no deletes
} else {
$delGen = ($delGenHigh << 32) | $delGenLow;
}
$hasSingleNormFile = $segmentsFile->readByte();
$numField = $segmentsFile->readInt();
$normGens = array();
if ($numField != (int)0xFFFFFFFF) {
for ($count1 = 0; $count1 < $numField; $count1++) {
$normGens[] = $segmentsFile->readLong();
}
throw new Zend_Search_Lucene_Exception('Separate norm files are not supported. Optimize index to use it with Zend_Search_Lucene.');
}
$isCompound = $segmentsFile->readByte();
$this->_docCount += $segSize;
$this->_segmentInfos[$segName] =
new Zend_Search_Lucene_Index_SegmentInfo($this->_directory,
$segName,
$segSize,
$delGen,
$hasSingleNormFile,
$isCompound);
}
}
/**
* Opens the index.
*
* IndexReader constructor needs Directory as a parameter. It should be
* a string with a path to the index folder or a Directory object.
*
* @param mixed $directory
* @throws Zend_Search_Lucene_Exception
*/
public function __construct($directory = null, $create = false)
{
if ($directory === null) {
throw new Zend_Search_Exception('No index directory specified');
}
if ($directory instanceof Zend_Search_Lucene_Storage_Directory_Filesystem) {
$this->_directory = $directory;
$this->_closeDirOnExit = false;
} else {
$this->_directory = new Zend_Search_Lucene_Storage_Directory_Filesystem($directory);
$this->_closeDirOnExit = true;
}
$this->_segmentInfos = array();
// Mark index as "under processing" to prevent other processes from premature index cleaning
Zend_Search_Lucene_LockManager::obtainReadLock($this->_directory);
// Escalate read lock to prevent current generation index files to be deleted while opening process is not done
Zend_Search_Lucene_LockManager::escalateReadLock($this->_directory);
$this->_generation = self::getActualGeneration($this->_directory);
if ($create) {
try {
Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory);
} catch (Zend_Search_Lucene_Exception $e) {
if (strpos($e->getMessage(), 'Can\'t obtain exclusive index lock') === false) {
throw $e;
} else {
throw new Zend_Search_Lucene_Exception('Can\'t create index. It\'s under processing now');
}
}
if ($this->_generation == -1) {
// Directory doesn't contain existing index, start from 1
$this->_generation = 1;
$nameCounter = 0;
} else {
// Directory contains existing index
$segmentsFile = $this->_directory->getFileObject(self::getSegmentFileName($this->_generation));
$segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version)
$nameCounter = $segmentsFile->readInt();
$this->_generation++;
}
Zend_Search_Lucene_Index_Writer::createIndex($this->_directory, $this->_generation, $nameCounter);
Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory);
}
if ($this->_generation == -1) {
throw new Zend_Search_Lucene_Exception('Index doesn\'t exists in the specified directory.');
} else if ($this->_generation == 0) {
$this->_readPre21SegmentsFile();
} else {
$this->_readSegmentsFile();
}
// De-escalate read lock to prevent current generation index files to be deleted while opening process is not done
Zend_Search_Lucene_LockManager::deEscalateReadLock($this->_directory);
}
/**
* Close current index and free resources
*/
@@ -267,9 +471,9 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
$this->commit();
// Free shared lock
$this->_lock->unlock();
// Release "under processing" flag
Zend_Search_Lucene_LockManager::releaseReadLock($this->_directory);
if ($this->_closeDirOnExit) {
$this->_directory->close();
}
@@ -431,6 +635,30 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
return self::$_defaultSearchField;
}
/**
* Set result set limit.
*
* 0 (default) means no limit
*
* @param integer $limit
*/
public static function setResultSetLimit($limit)
{
self::$_resultSetLimit = $limit;
}
/**
* Set result set limit.
*
* 0 means no limit
*
* @return integer
*/
public static function getResultSetLimit()
{
return self::$_resultSetLimit;
}
/**
* Retrieve index maxBufferedDocs option
*
@@ -585,11 +813,15 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
$topScore = $docScore;
}
}
if (self::$_resultSetLimit != 0 && count($hits) >= self::$_resultSetLimit) {
break;
}
}
if (count($hits) == 0) {
// skip sorting, which may cause a error on empty index
return array();
return array();
}
if ($topScore > 1) {
@@ -977,6 +1209,8 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
{
$this->getIndexWriter()->addDocument($document);
$this->_docCount++;
$this->_hasChanges = true;
}
@@ -1002,14 +1236,12 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
foreach ($this->_segmentInfos as $segInfo) {
$segInfo->writeChanges();
}
$this->_hasChanges = false;
}
if ($this->_writer !== null) {
$this->_writer->commit();
$this->getIndexWriter()->commit();
$this->_updateDocCount();
$this->_hasChanges = false;
}
}
@@ -1059,9 +1291,7 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
$result[] = $segmentInfo->currentTerm();
}
$segmentInfo->nextTerm();
// check, if segment dictionary is finished
if ($segmentInfo->currentTerm() !== null) {
if ($segmentInfo->nextTerm() !== null) {
// Put segment back into the priority queue
$segmentInfoQueue->put($segmentInfo);
}
@@ -1071,6 +1301,125 @@ class Zend_Search_Lucene implements Zend_Search_Lucene_Interface
}
/**
* Terms stream queue
*
* @var Zend_Search_Lucene_Index_SegmentInfoPriorityQueue
*/
private $_termsStreamQueue = null;
/**
* Last Term in a terms stream
*
* @var Zend_Search_Lucene_Index_Term
*/
private $_lastTerm = null;
/**
* Reset terms stream.
*/
public function resetTermsStream()
{
$this->_termsStreamQueue = new Zend_Search_Lucene_Index_SegmentInfoPriorityQueue();
foreach ($this->_segmentInfos as $segmentInfo) {
$segmentInfo->reset();
// Skip "empty" segments
if ($segmentInfo->currentTerm() !== null) {
$this->_termsStreamQueue->put($segmentInfo);
}
}
$this->nextTerm();
}
/**
* Skip terms stream up to specified term preffix.
*
* Prefix contains fully specified field info and portion of searched term
*
* @param Zend_Search_Lucene_Index_Term $prefix
*/
public function skipTo(Zend_Search_Lucene_Index_Term $prefix)
{
$segments = array();
while (($segmentInfo = $this->_termsStreamQueue->pop()) !== null) {
$segments[] = $segmentInfo;
}
foreach ($segments as $segmentInfo) {
$segmentInfo->skipTo($prefix);
if ($segmentInfo->currentTerm() !== null) {
$this->_termsStreamQueue->put($segmentInfo);
}
}
$this->nextTerm();
}
/**
* Scans terms dictionary and returns next term
*
* @return Zend_Search_Lucene_Index_Term|null
*/
public function nextTerm()
{
while (($segmentInfo = $this->_termsStreamQueue->pop()) !== null) {
if ($this->_termsStreamQueue->top() === null ||
$this->_termsStreamQueue->top()->currentTerm()->key() !=
$segmentInfo->currentTerm()->key()) {
// We got new term
$this->_lastTerm = $segmentInfo->currentTerm();
if ($segmentInfo->nextTerm() !== null) {
// Put segment back into the priority queue
$this->_termsStreamQueue->put($segmentInfo);
}
return $this->_lastTerm;
}
if ($segmentInfo->nextTerm() !== null) {
// Put segment back into the priority queue
$this->_termsStreamQueue->put($segmentInfo);
}
}
// End of stream
$this->_lastTerm = null;
return null;
}
/**
* Returns term in current position
*
* @return Zend_Search_Lucene_Index_Term|null
*/
public function currentTerm()
{
return $this->_lastTerm;
}
/**
* Close terms stream
*
* Should be used for resources clean up if stream is not read up to the end
*/
public function closeTermsStream()
{
while (($segmentInfo = $this->_termsStreamQueue->pop()) !== null) {
$segmentInfo->closeTermsStream();
}
$this->_termsStreamQueue = null;
$this->_lastTerm = null;
}
/*************************************************************************
@todo UNIMPLEMENTED
*************************************************************************/
+20 -13
View File
@@ -15,37 +15,43 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Token */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Token.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Token.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive */
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8/CaseInsensitive.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive */
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Utf8Num/CaseInsensitive.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Text */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text/CaseInsensitive.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text/CaseInsensitive.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php";
/** Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum/CaseInsensitive.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum/CaseInsensitive.php";
/** Zend_Search_Lucene_Analysis_TokenFilter_StopWords */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php';
require_once 'Zend/Search/Lucene/Analysis/TokenFilter/StopWords.php';
/** Zend_Search_Lucene_Analysis_TokenFilter_ShortWords */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter/ShortWords.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/TokenFilter/ShortWords.php";
/**
@@ -61,7 +67,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter/Shor
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -97,9 +103,10 @@ abstract class Zend_Search_Lucene_Analysis_Analyzer
* @param string $data
* @return array
*/
public function tokenize($data, $encoding = 'UTF-8')
public function tokenize($data, $encoding = '')
{
$this->setInput($data, $encoding);
$tokenList = array();
while (($nextToken = $this->nextToken()) !== null) {
$tokenList[] = $nextToken;
@@ -160,7 +167,7 @@ abstract class Zend_Search_Lucene_Analysis_Analyzer
public static function getDefault()
{
if (!self::$_defaultImpl instanceof Zend_Search_Lucene_Analysis_Analyzer) {
self::$_defaultImpl = new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8();
self::$_defaultImpl = new Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive();
}
return self::$_defaultImpl;
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer.php';
/**
@@ -34,7 +34,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Analysis_Analyzer_Common extends Zend_Search_Lucene_Analysis_Analyzer
@@ -68,7 +68,7 @@ abstract class Zend_Search_Lucene_Analysis_Analyzer_Common extends Zend_Search_L
foreach ($this->_filters as $filter) {
$token = $filter->normalize($token);
// resulting token can be null if the filter removed it
// resulting token can be null if the filter removes it
if (is_null($token)) {
return null;
}
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer_Common */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer/Common.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -53,7 +53,9 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Text extends Zend_Search_Lucen
}
// convert input into ascii
$this->_input = iconv($this->_encoding, 'ASCII//TRANSLIT', $this->_input);
//$this->_input = iconv($this->_encoding, 'ASCII//TRANSLIT', $this->_input);
$this->_input = mb_convert_encoding($this->_input, 'ASCII', 'auto');
$this->_encoding = 'ASCII';
}
@@ -75,7 +77,7 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Text extends Zend_Search_Lucen
if (! preg_match('/[a-zA-Z]+/', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_position)) {
// It covers both cases a) there are no matches (preg_match(...) === 0)
// b) error occured (preg_match(...) === FALSE)
return null;
return null;
}
$str = $match[0][0];
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer_Common_Text */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer/Common/Text.php';
/** Zend_Search_Lucene_Analysis_TokenFilter_LowerCase */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter/LowerCase.php';
require_once 'Zend/Search/Lucene/Analysis/TokenFilter/LowerCase.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer_Common */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer/Common.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -74,7 +74,7 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum extends Zend_Search_Lu
if (! preg_match('/[a-zA-Z0-9]+/', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_position)) {
// It covers both cases a) there are no matches (preg_match(...) === 0)
// b) error occured (preg_match(...) === FALSE)
return null;
return null;
}
$str = $match[0][0];
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer/Common/TextNum.php';
/** Zend_Search_Lucene_Analysis_TokenFilter_LowerCase */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter/LowerCase.php';
require_once 'Zend/Search/Lucene/Analysis/TokenFilter/LowerCase.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer_Common */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer/Common.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -47,13 +47,20 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 extends Zend_Search_Lucen
* @var integer
*/
private $_bytePosition;
/**
* Stream length
* Object constructor
*
* @var integer
* @throws Zend_Search_Lucene_Exception
*/
private $_streamLength;
public function __construct()
{
if (@preg_match('/\pL/u', 'a') != 1) {
// PCRE unicode support is turned off
require_once 'Zend/Search/Lucene/Exception.php';
throw new Zend_Search_Lucene_Exception('Utf8 analyzer needs PCRE unicode support to be enabled.');
}
}
/**
* Reset token stream
@@ -66,56 +73,9 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 extends Zend_Search_Lucen
// convert input into UTF-8
if (strcasecmp($this->_encoding, 'utf8' ) != 0 &&
strcasecmp($this->_encoding, 'utf-8') != 0 ) {
$this->_input = iconv($this->_encoding, 'UTF-8', $this->_input);
$this->_input = @iconv($this->_encoding, 'UTF-8', $this->_input);
$this->_encoding = 'UTF-8';
}
// Get UTF-8 string length.
// It also checks if it's a correct utf-8 string
$this->_streamLength = iconv_strlen($this->_input, 'UTF-8');
}
/**
* Check, that character is a letter
*
* @param string $char
* @return boolean
*/
private static function _isAlpha($char)
{
if (strlen($char) > 1) {
// It's an UTF-8 character
return true;
}
return ctype_alpha($char);
}
/**
* Get next UTF-8 char
*
* @param string $char
* @return boolean
*/
private function _nextChar()
{
$char = $this->_input[$this->_bytePosition++];
if (( ord($char) & 0xC0 ) == 0xC0) {
$addBytes = 1;
if (ord($char) & 0x20 ) {
$addBytes++;
if (ord($char) & 0x10 ) {
$addBytes++;
}
}
$char .= substr($this->_input, $this->_bytePosition, $addBytes);
$this->_bytePosition += $addBytes;
}
$this->_position++;
return $char;
}
/**
@@ -131,39 +91,35 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8 extends Zend_Search_Lucen
return null;
}
while ($this->_position < $this->_streamLength) {
// skip white space
while ($this->_position < $this->_streamLength &&
!self::_isAlpha($char = $this->_nextChar())) {
$char = '';
}
$termStartPosition = $this->_position - 1;
$termText = $char;
// read token
while ($this->_position < $this->_streamLength &&
self::_isAlpha($char = $this->_nextChar())) {
$termText .= $char;
}
// Empty token, end of stream.
if ($termText == '') {
do {
if (! preg_match('/[\p{L}]+/u', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_bytePosition)) {
// It covers both cases a) there are no matches (preg_match(...) === 0)
// b) error occured (preg_match(...) === FALSE)
return null;
}
$token = new Zend_Search_Lucene_Analysis_Token(
$termText,
$termStartPosition,
$this->_position - 1);
$token = $this->normalize($token);
if ($token !== null) {
return $token;
}
// Continue if token is skipped
}
// matched string
$matchedWord = $match[0][0];
// binary position of the matched word in the input stream
$binStartPos = $match[0][1];
// character position of the matched word in the input stream
$startPos = $this->_position +
iconv_strlen(substr($this->_input,
$this->_bytePosition,
$binStartPos - $this->_bytePosition),
'UTF-8');
// character postion of the end of matched word in the input stream
$endPos = $startPos + iconv_strlen($matchedWord, 'UTF-8');
return null;
$this->_bytePosition = $binStartPos + strlen($matchedWord);
$this->_position = $endPos;
$token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($matchedWord, $startPos, $endPos));
} while ($token === null); // try again if token is skipped
return $token;
}
}
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Analyzer_Common */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer/Common.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer/Common.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -49,11 +49,18 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num extends Zend_Search_Lu
private $_bytePosition;
/**
* Stream length
* Object constructor
*
* @var integer
* @throws Zend_Search_Lucene_Exception
*/
private $_streamLength;
public function __construct()
{
if (@preg_match('/\pL/u', 'a') != 1) {
// PCRE unicode support is turned off
require_once 'Zend/Search/Lucene/Exception.php';
throw new Zend_Search_Lucene_Exception('Utf8Num analyzer needs PCRE unicode support to be enabled.');
}
}
/**
* Reset token stream
@@ -69,53 +76,6 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num extends Zend_Search_Lu
$this->_input = iconv($this->_encoding, 'UTF-8', $this->_input);
$this->_encoding = 'UTF-8';
}
// Get UTF-8 string length.
// It also checks if it's a correct utf-8 string
$this->_streamLength = iconv_strlen($this->_input, 'UTF-8');
}
/**
* Check, that character is a letter
*
* @param string $char
* @return boolean
*/
private static function _isAlNum($char)
{
if (strlen($char) > 1) {
// It's an UTF-8 character
return true;
}
return ctype_alnum($char);
}
/**
* Get next UTF-8 char
*
* @param string $char
* @return boolean
*/
private function _nextChar()
{
$char = $this->_input[$this->_bytePosition++];
if (( ord($char) & 0xC0 ) == 0xC0) {
$addBytes = 1;
if (ord($char) & 0x20 ) {
$addBytes++;
if (ord($char) & 0x10 ) {
$addBytes++;
}
}
$char .= substr($this->_input, $this->_bytePosition, $addBytes);
$this->_bytePosition += $addBytes;
}
$this->_position++;
return $char;
}
/**
@@ -131,39 +91,35 @@ class Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num extends Zend_Search_Lu
return null;
}
while ($this->_position < $this->_streamLength) {
// skip white space
while ($this->_position < $this->_streamLength &&
!self::_isAlNum($char = $this->_nextChar())) {
$char = '';
}
$termStartPosition = $this->_position - 1;
$termText = $char;
// read token
while ($this->_position < $this->_streamLength &&
self::_isAlNum($char = $this->_nextChar())) {
$termText .= $char;
}
// Empty token, end of stream.
if ($termText == '') {
do {
if (! preg_match('/[\p{L}\p{N}]+/u', $this->_input, $match, PREG_OFFSET_CAPTURE, $this->_bytePosition)) {
// It covers both cases a) there are no matches (preg_match(...) === 0)
// b) error occured (preg_match(...) === FALSE)
return null;
}
$token = new Zend_Search_Lucene_Analysis_Token(
$termText,
$termStartPosition,
$this->_position - 1);
$token = $this->normalize($token);
if ($token !== null) {
return $token;
}
// Continue if token is skipped
}
// matched string
$matchedWord = $match[0][0];
// binary position of the matched word in the input stream
$binStartPos = $match[0][1];
// character position of the matched word in the input stream
$startPos = $this->_position +
iconv_strlen(substr($this->_input,
$this->_bytePosition,
$binStartPos - $this->_bytePosition),
'UTF-8');
// character postion of the end of matched word in the input stream
$endPos = $startPos + iconv_strlen($matchedWord, 'UTF-8');
return null;
$this->_bytePosition = $binStartPos + strlen($matchedWord);
$this->_position = $endPos;
$token = $this->normalize(new Zend_Search_Lucene_Analysis_Token($matchedWord, $startPos, $endPos));
} while ($token === null); // try again if token is skipped
return $token;
}
}
+2 -2
View File
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -24,7 +24,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Analysis_Token
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_Token */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Token.php';
require_once 'Zend/Search/Lucene/Analysis/Token.php';
/**
@@ -30,7 +30,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Token.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_TokenFilter */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter.php';
require_once 'Zend/Search/Lucene/Analysis/TokenFilter.php';
/**
@@ -30,7 +30,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter.php'
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -21,7 +21,7 @@
/** Zend_Search_Lucene_Analysis_TokenFilter */
require_once 'Zend/Search/Lucene/Analysis/TokenFilter.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Analysis/TokenFilter.php";
/**
@@ -41,9 +41,10 @@ class Zend_Search_Lucene_Analysis_TokenFilter_LowerCaseUtf8 extends Zend_Search_
*/
public function __construct()
{
global $CFG;
if (!function_exists('mb_strtolower')) {
// mbstring extension is disabled
require_once 'Zend/Search/Lucene/Exception.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Exception.php";
throw new Zend_Search_Lucene_Exception('Utf8 compatible lower case filter needs mbstring extension to be enabled.');
}
}
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_TokenFilter */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter.php';
require_once 'Zend/Search/Lucene/Analysis/TokenFilter.php';
/**
@@ -30,7 +30,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter.php'
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -15,14 +15,14 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Analysis_TokenFilter */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/TokenFilter.php';
require_once $CFG->dirroot.'/search/Zend/Search/Exception.php';
require_once 'Zend/Search/Lucene/Analysis/TokenFilter.php';
require_once 'Zend/Search/Exception.php';
/**
@@ -34,14 +34,14 @@ require_once $CFG->dirroot.'/search/Zend/Search/Exception.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Analysis
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Analysis_TokenFilter_StopWords extends Zend_Search_Lucene_Analysis_TokenFilter
{
/**
* Minimum allowed term length
* Stop Words
* @var array
*/
private $_stopSet;
@@ -63,7 +63,6 @@ class Zend_Search_Lucene_Analysis_TokenFilter_StopWords extends Zend_Search_Luce
*/
public function normalize(Zend_Search_Lucene_Analysis_Token $srcToken) {
if (array_key_exists($srcToken->getTermText(), $this->_stopSet)) {
$t = $srcToken->getTermText();
return null;
} else {
return $srcToken;
+10 -10
View File
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Document
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Field */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Field.php';
require_once "Zend/Search/Lucene/Field.php";
/**
@@ -30,7 +30,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Field.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Document
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Document
@@ -54,10 +54,10 @@ class Zend_Search_Lucene_Document
* @param $offset
* @return string
*/
public function __get($offset)
{
return $this->getFieldValue($offset);
}
public function __get($offset)
{
return $this->getFieldValue($offset);
}
/**
@@ -78,7 +78,7 @@ class Zend_Search_Lucene_Document
*/
public function getFieldNames()
{
return array_keys($this->_fields);
return array_keys($this->_fields);
}
@@ -105,7 +105,7 @@ class Zend_Search_Lucene_Document
*/
public function getFieldValue($fieldName)
{
return $this->getField($fieldName)->value;
return $this->getField($fieldName)->value;
}
/**
@@ -116,6 +116,6 @@ class Zend_Search_Lucene_Document
*/
public function getFieldUtf8Value($fieldName)
{
return $this->getField($fieldName)->getUtf8Value();
return $this->getField($fieldName)->getUtf8Value();
}
}
+4 -4
View File
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Document
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Document */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Document.php';
require_once 'Zend/Search/Lucene/Document.php';
/**
@@ -30,7 +30,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Document.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Document
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Document_Html extends Zend_Search_Lucene_Document
@@ -290,7 +290,7 @@ class Zend_Search_Lucene_Document_Html extends Zend_Search_Lucene_Document
$xpath = new DOMXPath($this->_doc);
$matchedNodes = $xpath->query("/html/body/*");
$matchedNodes = $xpath->query("/html/body");
foreach ($matchedNodes as $matchedNode) {
$this->_highlightNode($matchedNode, $wordsToHighlightFlipped, $color);
}
+3 -3
View File
@@ -14,7 +14,7 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -22,13 +22,13 @@
/**
* Framework base exception
*/
require_once $CFG->dirroot.'/search/Zend/Search/Exception.php';
require_once "Zend/Search/Exception.php";
/**
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Exception extends Zend_Search_Exception
+4 -4
View File
@@ -14,16 +14,16 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_FSMAction */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/FSMAction.php';
require_once 'Zend/Search/Lucene/FSMAction.php';
/** Zend_Search_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Exception.php';
require_once 'Zend/Search/Exception.php';
/**
@@ -37,7 +37,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Exception.php';
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_FSM
+2 -2
View File
@@ -14,7 +14,7 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -25,7 +25,7 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_FSMAction
+2 -2
View File
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Document
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -31,7 +31,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Document
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Field
@@ -15,13 +15,13 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
@@ -35,7 +35,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_DictionaryLoader
@@ -61,11 +61,12 @@ class Zend_Search_Lucene_Index_DictionaryLoader
// $tiVersion = $tiiFile->readInt();
$tiVersion = ord($data[0]) << 24 | ord($data[1]) << 16 | ord($data[2]) << 8 | ord($data[3]);
$pos += 4;
if ($tiVersion != (int)0xFFFFFFFE) {
if ($tiVersion != (int)0xFFFFFFFE /* pre-2.1 format */ &&
$tiVersion != (int)0xFFFFFFFD /* 2.1+ format */) {
throw new Zend_Search_Lucene_Exception('Wrong TermInfoIndexFile file format');
}
// $indexTermCount = = $tiiFile->readLong();
// $indexTermCount = $tiiFile->readLong();
if (PHP_INT_SIZE > 4) {
$indexTermCount = ord($data[$pos]) << 56 |
ord($data[$pos+1]) << 48 |
@@ -101,6 +102,11 @@ class Zend_Search_Lucene_Index_DictionaryLoader
throw new Zend_Search_Lucene_Exception('Wrong number of terms in a term dictionary index');
}
if ($tiVersion == (int)0xFFFFFFFD /* 2.1+ format */) {
/* Skip MaxSkipLevels value */
$pos += 4;
}
$prevTerm = '';
$freqPointer = 0;
$proxPointer = 0;
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -24,7 +24,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_FieldInfo
+553 -121
View File
@@ -15,23 +15,30 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_DictionaryLoader */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/DictionaryLoader.php';
require_once 'Zend/Search/Lucene/Index/DictionaryLoader.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_LockManager */
if (@$CFG->block_search_softlock){
require_once "Zend/Search/Lucene/SoftLockManager.php";
} else {
require_once "Zend/Search/Lucene/LockManager.php";
}
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_SegmentInfo
@@ -110,6 +117,35 @@ class Zend_Search_Lucene_Index_SegmentInfo
*/
private $_segFileSizes;
/**
* Delete file generation number
*
* -1 means 'there is no delete file'
* 0 means pre-2.1 format delete file
* X specifies used delete file
*
* @var integer
*/
private $_delGen;
/**
* Segment has single norms file
*
* If true then one .nrm file is used for all fields
* Otherwise .fN files are used
*
* @var boolean
*/
private $_hasSingleNormFile;
/**
* Use compound segment file (*.cfs) to collect all other segment files
* (excluding .del files)
*
* @var boolean
*/
private $_isCompound;
/**
* File system adapter.
@@ -136,7 +172,7 @@ class Zend_Search_Lucene_Index_SegmentInfo
*
* @var mixed
*/
private $_deleted;
private $_deleted = null;
/**
* $this->_deleted update flag
@@ -147,22 +183,45 @@ class Zend_Search_Lucene_Index_SegmentInfo
/**
* Zend_Search_Lucene_Index_SegmentInfo constructor needs Segmentname,
* Documents count and Directory as a parameter.
* Zend_Search_Lucene_Index_SegmentInfo constructor
*
* @param Zend_Search_Lucene_Storage_Directory $directory
* @param string $name
* @param integer $docCount
* @param Zend_Search_Lucene_Storage_Directory $directory
* @param integer $delGen
* @param boolean $isCompound
*/
public function __construct($name, $docCount, $directory)
public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name, $docCount, $delGen = 0, $hasSingleNormFile = false, $isCompound = null)
{
$this->_name = $name;
$this->_docCount = $docCount;
$this->_directory = $directory;
$this->_termDictionary = null;
$this->_name = $name;
$this->_docCount = $docCount;
$this->_hasSingleNormFile = $hasSingleNormFile;
$this->_delGen = $delGen;
$this->_termDictionary = null;
if (!is_null($isCompound)) {
$this->_isCompound = $isCompound;
} else {
// It's a pre-2.1 segment
// detect if it uses compond file
$this->_isCompound = true;
try {
// Try to open compound file
$this->_directory->getFileObject($name . '.cfs');
} catch (Zend_Search_Lucene_Exception $e) {
if (strpos($e->getMessage(), 'is not readable') !== false) {
// Compound file is not found or is not readable
$this->_isCompound = false;
} else {
throw $e;
}
}
}
$this->_segFiles = array();
if ($this->_directory->fileExists($name . '.cfs')) {
if ($this->_isCompound) {
$cfsFile = $this->_directory->getFileObject($name . '.cfs');
$segFilesCount = $cfsFile->readVInt();
@@ -202,37 +261,83 @@ class Zend_Search_Lucene_Index_SegmentInfo
array_multisort($fieldNames, SORT_ASC, SORT_REGULAR, $fieldNums);
$this->_fieldsDicPositions = array_flip($fieldNums);
try {
$delFile = $this->openCompoundFile('.del');
if ($this->_delGen == -1) {
// There is no delete file for this segment
// Do nothing
} else if ($this->_delGen == 0) {
// It's a segment with pre-2.1 format delete file
// Try to find delete file
try {
// '.del' files always stored in a separate file
// Segment compound is not used
$delFile = $this->_directory->getFileObject($this->_name . '.del');
$byteCount = $delFile->readInt();
$byteCount = ceil($byteCount/8);
$bitCount = $delFile->readInt();
$byteCount = $delFile->readInt();
$byteCount = ceil($byteCount/8);
$bitCount = $delFile->readInt();
if ($bitCount == 0) {
$delBytes = '';
} else {
$delBytes = $delFile->readBytes($byteCount);
}
if ($bitCount == 0) {
$delBytes = '';
} else {
$delBytes = $delFile->readBytes($byteCount);
}
if (extension_loaded('bitset')) {
$this->_deleted = $delBytes;
} else {
$this->_deleted = array();
for ($count = 0; $count < $byteCount; $count++) {
$byte = ord($delBytes{$count});
for ($bit = 0; $bit < 8; $bit++) {
if ($byte & (1<<$bit)) {
$this->_deleted[$count*8 + $bit] = 1;
if (extension_loaded('bitset')) {
$this->_deleted = $delBytes;
} else {
$this->_deleted = array();
for ($count = 0; $count < $byteCount; $count++) {
$byte = ord($delBytes{$count});
for ($bit = 0; $bit < 8; $bit++) {
if ($byte & (1<<$bit)) {
$this->_deleted[$count*8 + $bit] = 1;
}
}
}
}
} catch(Zend_Search_Exception $e) {
if (strpos($e->getMessage(), 'is not readable') === false ) {
throw $e;
}
// There is no delete file
// Do nothing
}
} catch(Zend_Search_Exception $e) {
if (strpos($e->getMessage(), 'compound file doesn\'t contain') !== false ) {
$this->_deleted = null;
} else {
// It's 2.1+ format delete file
$delFile = $this->_directory->getFileObject($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del');
$format = $delFile->readInt();
if ($format == (int)0xFFFFFFFF) {
/**
* @todo Implement support of DGaps delete file format.
* See Lucene file format for details - http://lucene.apache.org/java/docs/fileformats.html#Deleted%20Documents
*/
throw new Zend_Search_Lucene_Exception('DGaps delete file format is not supported. Optimize index to use it with Zend_Search_Lucene');
} else {
throw $e;
// $format is actually byte count
$byteCount = ceil($format/8);
$bitCount = $delFile->readInt();
if ($bitCount == 0) {
$delBytes = '';
} else {
$delBytes = $delFile->readBytes($byteCount);
}
if (extension_loaded('bitset')) {
$this->_deleted = $delBytes;
} else {
$this->_deleted = array();
for ($count = 0; $count < $byteCount; $count++) {
$byte = ord($delBytes{$count});
for ($bit = 0; $bit < 8; $bit++) {
if ($byte & (1<<$bit)) {
$this->_deleted[$count*8 + $bit] = 1;
}
}
}
}
}
}
}
@@ -249,13 +354,12 @@ class Zend_Search_Lucene_Index_SegmentInfo
{
$filename = $this->_name . $extension;
// Try to open common file first
if ($this->_directory->fileExists($filename)) {
if (!$this->_isCompound) {
return $this->_directory->getFileObject($filename, $shareHandler);
}
if( !isset($this->_segFiles[$filename]) ) {
throw new Zend_Search_Lucene_Exception('Index compound file doesn\'t contain '
throw new Zend_Search_Lucene_Exception('Segment compound file doesn\'t contain '
. $filename . ' file.' );
}
@@ -343,6 +447,16 @@ class Zend_Search_Lucene_Index_SegmentInfo
return $this->_fields;
}
/**
* Returns actual deletions file generation number.
*
* @return integer
*/
public function getDelGen()
{
return $this->_delGen;
}
/**
* Returns the total number of documents in this segment (including deleted documents).
*
@@ -431,6 +545,41 @@ class Zend_Search_Lucene_Index_SegmentInfo
}
}
/**
* Load terms dictionary index
*
* @throws Zend_Search_Lucene_Exception
*/
private function _loadDictionaryIndex()
{
// Check, if index is already serialized
if ($this->_directory->fileExists($this->_name . '.sti')) {
// Load serialized dictionary index data
$stiFile = $this->_directory->getFileObject($this->_name . '.sti');
$stiFileData = $stiFile->readBytes($this->_directory->fileLength($this->_name . '.sti'));
// Load dictionary index data
if (($unserializedData = @unserialize($stiFileData)) !== false) {
list($this->_termDictionary, $this->_termDictionaryInfos) = $unserializedData;
return;
}
}
// Load data from .tii file and generate .sti file
// Prefetch dictionary index data
$tiiFile = $this->openCompoundFile('.tii');
$tiiFileData = $tiiFile->readBytes($this->compoundFileLength('.tii'));
// Load dictionary index data
list($this->_termDictionary, $this->_termDictionaryInfos) =
Zend_Search_Lucene_Index_DictionaryLoader::load($tiiFileData);
$stiFileData = serialize(array($this->_termDictionary, $this->_termDictionaryInfos));
$stiFile = $this->_directory->createFile($this->_name . '.sti');
$stiFile->writeBytes($stiFileData);
}
/**
* Scans terms dictionary and returns term info
*
@@ -452,32 +601,9 @@ class Zend_Search_Lucene_Index_SegmentInfo
if ($this->_termDictionary === null) {
// Check, if index is already serialized
if ($this->_directory->fileExists($this->_name . '.sti')) {
// Prefetch dictionary index data
$stiFile = $this->_directory->getFileObject($this->_name . '.sti');
$stiFileData = $stiFile->readBytes($this->_directory->fileLength($this->_name . '.sti'));
// Load dictionary index data
list($this->_termDictionary, $this->_termDictionaryInfos) = unserialize($stiFileData);
} else {
// Prefetch dictionary index data
$tiiFile = $this->openCompoundFile('.tii');
$tiiFileData = $tiiFile->readBytes($this->compoundFileLength('.tii'));
// Load dictionary index data
list($this->_termDictionary, $this->_termDictionaryInfos) =
Zend_Search_Lucene_Index_DictionaryLoader::load($tiiFileData);
$stiFileData = serialize(array($this->_termDictionary, $this->_termDictionaryInfos));
$stiFile = $this->_directory->createFile($this->_name . '.sti');
$stiFile->writeBytes($stiFileData);
}
$this->_loadDictionaryIndex();
}
$searchField = $this->getFieldNum($term->field);
if ($searchField == -1) {
@@ -526,15 +652,19 @@ class Zend_Search_Lucene_Index_SegmentInfo
$tisFile = $this->openCompoundFile('.tis');
$tiVersion = $tisFile->readInt();
if ($tiVersion != (int)0xFFFFFFFE) {
if ($tiVersion != (int)0xFFFFFFFE /* pre-2.1 format */ &&
$tiVersion != (int)0xFFFFFFFD /* 2.1+ format */) {
throw new Zend_Search_Lucene_Exception('Wrong TermInfoFile file format');
}
$termCount = $tisFile->readLong();
$indexInterval = $tisFile->readInt();
$skipInterval = $tisFile->readInt();
if ($tiVersion == (int)0xFFFFFFFD /* 2.1+ format */) {
$maxSkipLevels = $tisFile->readInt();
}
$tisFile->seek($prevTermInfo[4] /* indexPointer */ - 20 /* header size*/, SEEK_CUR);
$tisFile->seek($prevTermInfo[4] /* indexPointer */ - (($tiVersion == (int)0xFFFFFFFD)? 24 : 20) /* header size*/, SEEK_CUR);
$termValue = $prevTerm[1] /* text */;
$termFieldNum = $prevTerm[0] /* field */;
@@ -666,11 +796,29 @@ class Zend_Search_Lucene_Index_SegmentInfo
* Load normalizatin factors from an index file
*
* @param integer $fieldNum
* @throws Zend_Search_Lucene_Exception
*/
private function _loadNorm($fieldNum)
{
$fFile = $this->openCompoundFile('.f' . $fieldNum);
$this->_norms[$fieldNum] = $fFile->readBytes($this->_docCount);
if ($this->_hasSingleNormFile) {
$normfFile = $this->openCompoundFile('.nrm');
$header = $normfFile->readBytes(3);
$headerFormatVersion = $normfFile->readByte();
if ($header != 'NRM' || $headerFormatVersion != (int)0xFF) {
throw new Zend_Search_Lucene_Exception('Wrong norms file format.');
}
foreach ($this->_fields as $fieldNum => $fieldInfo) {
if ($fieldInfo->isIndexed) {
$this->_norms[$fieldNum] = $normfFile->readBytes($this->_docCount);
}
}
} else {
$fFile = $this->openCompoundFile('.f' . $fieldNum);
$this->_norms[$fieldNum] = $fFile->readBytes($this->_docCount);
}
}
/**
@@ -731,6 +879,26 @@ class Zend_Search_Lucene_Index_SegmentInfo
}
/**
* Returns true if segment has single norms file.
*
* @return boolean
*/
public function hasSingleNormFile()
{
return $this->_hasSingleNormFile ? 1 : 0;
}
/**
* Returns true if segment is stored using compound segment file.
*
* @return boolean
*/
public function isCompound()
{
return $this->_isCompound ? 1 : 0;
}
/**
* Deletes a document from the index segment.
* $id is an internal document id
@@ -803,7 +971,35 @@ class Zend_Search_Lucene_Index_SegmentInfo
}
$delFile = $this->_directory->createFile($this->_name . '.del');
// Get new generation number
Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory);
$delFileList = array();
foreach ($this->_directory->fileList() as $file) {
if ($file == $this->_name . '.del') {
// Matches <segment_name>.del file name
$delFileList[] = 0;
} else if (preg_match('/^' . $this->_name . '_([a-zA-Z0-9]+)\.del$/i', $file, $matches)) {
// Matches <segment_name>_NNN.del file names
$delFileList[] = (int)base_convert($matches[1], 36, 10);
}
}
if (count($delFileList) == 0) {
// There is no deletions file for current segment in the directory
// Set detetions file generation number to 1
$this->_delGen = 1;
} else {
// There are some deletions files for current segment in the directory
// Set detetions file generation number to the highest + 1
$this->_delGen = max($delFileList) + 1;
}
$delFile = $this->_directory->createFile($this->_name . '_' . base_convert($this->_delGen, 10, 36) . '.del');
Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory);
$delFile->writeInt($this->_docCount);
$delFile->writeInt($bitCount);
$delFile->writeBytes($delBytes);
@@ -820,6 +1016,13 @@ class Zend_Search_Lucene_Index_SegmentInfo
*/
private $_tisFile = null;
/**
* Actual offset of the .tis file data
*
* @var integer
*/
private $_tisFileOffset;
/**
* Frequencies File object for stream like terms reading
*
@@ -828,7 +1031,7 @@ class Zend_Search_Lucene_Index_SegmentInfo
private $_frqFile = null;
/**
* Offset of the .frq file in the compound file
* Actual offset of the .frq file data
*
* @var integer
*/
@@ -842,7 +1045,7 @@ class Zend_Search_Lucene_Index_SegmentInfo
private $_prxFile = null;
/**
* Offset of the .prx file in the compound file
* Actual offset of the .prx file in the compound file
*
* @var integer
*/
@@ -850,12 +1053,26 @@ class Zend_Search_Lucene_Index_SegmentInfo
/**
* Number of terms in term stream
* Actual number of terms in term stream
*
* @var integer
*/
private $_termCount = 0;
/**
* Overall number of terms in term stream
*
* @var integer
*/
private $_termNum = 0;
/**
* Segment index interval
*
* @var integer
*/
private $_indexInterval;
/**
* Segment skip interval
*
@@ -891,10 +1108,32 @@ class Zend_Search_Lucene_Index_SegmentInfo
* An array of all term positions in the documents.
* Array structure: array( docId => array( pos1, pos2, ...), ...)
*
* @var array
* Is set to null if term positions loading has to be skipped
*
* @var array|null
*/
private $_lastTermPositions;
/**
* Terms scan mode
*
* Values:
*
* self::SM_TERMS_ONLY - terms are scanned, no additional info is retrieved
* self::SM_MERGE_INFO - terms are scanned, frequency and position info is retrieved
* document numbers are compacted (shifted if segment has deleted documents)
*
* @var integer
*/
private $_termsScanMode;
/** Scan modes */
const SM_TERMS_ONLY = 0; // terms are scanned, no additional info is retrieved
const SM_FULL_INFO = 1; // terms are scanned, frequency and position info is retrieved
const SM_MERGE_INFO = 2; // terms are scanned, frequency and position info is retrieved
// document numbers are compacted (shifted if segment contains deleted documents)
/**
* Reset terms stream
*
@@ -904,50 +1143,223 @@ class Zend_Search_Lucene_Index_SegmentInfo
* Returns start document id for the next segment
*
* @param integer $startId
* @param boolean $compact
* @param integer $mode
* @throws Zend_Search_Lucene_Exception
* @return integer
*/
public function reset($startId = 0, $compact = false)
public function reset($startId = 0, $mode = self::SM_TERMS_ONLY)
{
if ($this->_tisFile !== null) {
$this->_tisFile = null;
}
$this->_tisFile = $this->openCompoundFile('.tis', false);
$this->_tisFileOffset = $this->_tisFile->tell();
$tiVersion = $this->_tisFile->readInt();
if ($tiVersion != (int)0xFFFFFFFE) {
if ($tiVersion != (int)0xFFFFFFFE /* pre-2.1 format */ &&
$tiVersion != (int)0xFFFFFFFD /* 2.1+ format */) {
throw new Zend_Search_Lucene_Exception('Wrong TermInfoFile file format');
}
$this->_termCount = $this->_tisFile->readLong();
$this->_tisFile->readInt(); // Read Index interval
$this->_skipInterval = $this->_tisFile->readInt(); // Read skip interval
$this->_termCount =
$this->_termNum = $this->_tisFile->readLong(); // Read terms count
$this->_indexInterval = $this->_tisFile->readInt(); // Read Index interval
$this->_skipInterval = $this->_tisFile->readInt(); // Read skip interval
if ($tiVersion == (int)0xFFFFFFFD /* 2.1+ format */) {
$maxSkipLevels = $this->_tisFile->readInt();
}
if ($this->_frqFile !== null) {
$this->_frqFile = null;
}
$this->_frqFile = $this->openCompoundFile('.frq', false);
$this->_frqFileOffset = $this->_frqFile->tell();
if ($this->_prxFile !== null) {
$this->_prxFile = null;
}
$this->_prxFile = $this->openCompoundFile('.prx', false);
$this->_prxFileOffset = $this->_prxFile->tell();
$this->_lastTerm = new Zend_Search_Lucene_Index_Term('', -1);
$this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo(0, 0, 0, 0);
$this->_docMap = array();
for ($count = 0; $count < $this->_docCount; $count++) {
if (!$this->isDeleted($count)) {
$this->_docMap[$count] = $startId + ($compact ? count($this->_docMap) : $count);
$this->_lastTerm = new Zend_Search_Lucene_Index_Term('', -1);
$this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo(0, 0, 0, 0);
$this->_lastTermPositions = null;
$this->_termsScanMode = $mode;
switch ($mode) {
case self::SM_TERMS_ONLY:
// Do nothing
break;
case self::SM_FULL_INFO:
// break intentionally omitted
case self::SM_MERGE_INFO:
$this->_frqFile = $this->openCompoundFile('.frq', false);
$this->_frqFileOffset = $this->_frqFile->tell();
$this->_prxFile = $this->openCompoundFile('.prx', false);
$this->_prxFileOffset = $this->_prxFile->tell();
for ($count = 0; $count < $this->_docCount; $count++) {
if (!$this->isDeleted($count)) {
$this->_docMap[$count] = $startId + (($mode == self::SM_MERGE_INFO) ? count($this->_docMap) : $count);
}
}
break;
default:
throw new Zend_Search_Lucene_Exception('Wrong terms scaning mode specified.');
break;
}
$this->nextTerm();
return $startId + (($mode == self::SM_MERGE_INFO) ? count($this->_docMap) : $this->_docCount);
}
/**
* Skip terms stream up to specified term preffix.
*
* Prefix contains fully specified field info and portion of searched term
*
* @param Zend_Search_Lucene_Index_Term $prefix
* @throws Zend_Search_Lucene_Exception
*/
public function skipTo(Zend_Search_Lucene_Index_Term $prefix)
{
if ($this->_termDictionary === null) {
$this->_loadDictionaryIndex();
}
$searchField = $this->getFieldNum($prefix->field);
if ($searchField == -1) {
/**
* Field is not presented in this segment
* Go to the end of dictionary
*/
$this->_tisFile = null;
$this->_frqFile = null;
$this->_prxFile = null;
$this->_lastTerm = null;
$this->_lastTermInfo = null;
$this->_lastTermPositions = null;
return;
}
$searchDicField = $this->_getFieldPosition($searchField);
// search for appropriate value in dictionary
$lowIndex = 0;
$highIndex = count($this->_termDictionary)-1;
while ($highIndex >= $lowIndex) {
// $mid = ($highIndex - $lowIndex)/2;
$mid = ($highIndex + $lowIndex) >> 1;
$midTerm = $this->_termDictionary[$mid];
$fieldNum = $this->_getFieldPosition($midTerm[0] /* field */);
$delta = $searchDicField - $fieldNum;
if ($delta == 0) {
$delta = strcmp($prefix->text, $midTerm[1] /* text */);
}
if ($delta < 0) {
$highIndex = $mid-1;
} elseif ($delta > 0) {
$lowIndex = $mid+1;
} else {
// We have reached term we are looking for
break;
}
}
$this->nextTerm();
return $startId + ($compact ? count($this->_docMap) : $this->_docCount);
if ($highIndex == -1) {
// Term is out of the dictionary range
$this->_tisFile = null;
$this->_frqFile = null;
$this->_prxFile = null;
$this->_lastTerm = null;
$this->_lastTermInfo = null;
$this->_lastTermPositions = null;
return;
}
$prevPosition = $highIndex;
$prevTerm = $this->_termDictionary[$prevPosition];
$prevTermInfo = $this->_termDictionaryInfos[$prevPosition];
if ($this->_tisFile === null) {
// The end of terms stream is reached and terms dictionary file is closed
// Perform mini-reset operation
$this->_tisFile = $this->openCompoundFile('.tis', false);
if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) {
$this->_frqFile = $this->openCompoundFile('.frq', false);
$this->_prxFile = $this->openCompoundFile('.prx', false);
}
}
$this->_tisFile->seek($this->_tisFileOffset + $prevTermInfo[4], SEEK_SET);
$this->_lastTerm = new Zend_Search_Lucene_Index_Term($prevTerm[1] /* text */,
($prevTerm[0] == -1) ? '' : $this->_fields[$prevTerm[0] /* field */]->name);
$this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo($prevTermInfo[0] /* docFreq */,
$prevTermInfo[1] /* freqPointer */,
$prevTermInfo[2] /* proxPointer */,
$prevTermInfo[3] /* skipOffset */);
$this->_termCount = $this->_termNum - $prevPosition*$this->_indexInterval;
if ($highIndex == 0) {
// skip start entry
$this->nextTerm();
} else if ($prefix->field == $this->_lastTerm->field && $prefix->text == $this->_lastTerm->text) {
// We got exact match in the dictionary index
if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) {
$this->_lastTermPositions = array();
$this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET);
$freqs = array(); $docId = 0;
for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) {
$docDelta = $this->_frqFile->readVInt();
if( $docDelta % 2 == 1 ) {
$docId += ($docDelta-1)/2;
$freqs[ $docId ] = 1;
} else {
$docId += $docDelta/2;
$freqs[ $docId ] = $this->_frqFile->readVInt();
}
}
$this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET);
foreach ($freqs as $docId => $freq) {
$termPosition = 0; $positions = array();
for ($count = 0; $count < $freq; $count++ ) {
$termPosition += $this->_prxFile->readVInt();
$positions[] = $termPosition;
}
if (isset($this->_docMap[$docId])) {
$this->_lastTermPositions[$this->_docMap[$docId]] = $positions;
}
}
}
return;
}
// Search term matching specified prefix
while ($this->_lastTerm !== null) {
if ( strcmp($this->_lastTerm->field, $prefix->field) > 0 ||
($prefix->field == $this->_lastTerm->field && strcmp($this->_lastTerm->text, $prefix->text) >= 0) ) {
// Current term matches or greate than the pattern
return;
}
$this->nextTerm();
}
}
@@ -959,8 +1371,10 @@ class Zend_Search_Lucene_Index_SegmentInfo
public function nextTerm()
{
if ($this->_tisFile === null || $this->_termCount == 0) {
$this->_lastTerm = null;
$this->_lastTermInfo = null;
$this->_lastTerm = null;
$this->_lastTermInfo = null;
$this->_lastTermPositions = null;
$this->_docMap = null;
// may be necessary for "empty" segment
$this->_tisFile = null;
@@ -989,36 +1403,37 @@ class Zend_Search_Lucene_Index_SegmentInfo
$this->_lastTermInfo = new Zend_Search_Lucene_Index_TermInfo($docFreq, $freqPointer, $proxPointer, $skipOffset);
$this->_lastTermPositions = array();
if ($this->_termsScanMode == self::SM_FULL_INFO || $this->_termsScanMode == self::SM_MERGE_INFO) {
$this->_lastTermPositions = array();
$this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET);
$freqs = array(); $docId = 0;
for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) {
$docDelta = $this->_frqFile->readVInt();
if( $docDelta % 2 == 1 ) {
$docId += ($docDelta-1)/2;
$freqs[ $docId ] = 1;
} else {
$docId += $docDelta/2;
$freqs[ $docId ] = $this->_frqFile->readVInt();
$this->_frqFile->seek($this->_lastTermInfo->freqPointer + $this->_frqFileOffset, SEEK_SET);
$freqs = array(); $docId = 0;
for( $count = 0; $count < $this->_lastTermInfo->docFreq; $count++ ) {
$docDelta = $this->_frqFile->readVInt();
if( $docDelta % 2 == 1 ) {
$docId += ($docDelta-1)/2;
$freqs[ $docId ] = 1;
} else {
$docId += $docDelta/2;
$freqs[ $docId ] = $this->_frqFile->readVInt();
}
}
$this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET);
foreach ($freqs as $docId => $freq) {
$termPosition = 0; $positions = array();
for ($count = 0; $count < $freq; $count++ ) {
$termPosition += $this->_prxFile->readVInt();
$positions[] = $termPosition;
}
if (isset($this->_docMap[$docId])) {
$this->_lastTermPositions[$this->_docMap[$docId]] = $positions;
}
}
}
$this->_prxFile->seek($this->_lastTermInfo->proxPointer + $this->_prxFileOffset, SEEK_SET);
foreach ($freqs as $docId => $freq) {
$termPosition = 0; $positions = array();
for ($count = 0; $count < $freq; $count++ ) {
$termPosition += $this->_prxFile->readVInt();
$positions[] = $termPosition;
}
if (isset($this->_docMap[$docId])) {
$this->_lastTermPositions[$this->_docMap[$docId]] = $positions;
}
}
$this->_termCount--;
if ($this->_termCount == 0) {
$this->_tisFile = null;
@@ -1029,11 +1444,28 @@ class Zend_Search_Lucene_Index_SegmentInfo
return $this->_lastTerm;
}
/**
* Close terms stream
*
* Should be used for resources clean up if stream is not read up to the end
*/
public function closeTermsStream()
{
$this->_tisFile = null;
$this->_frqFile = null;
$this->_prxFile = null;
$this->_lastTerm = null;
$this->_lastTermInfo = null;
$this->_lastTermPositions = null;
$this->_docMap = null;
}
/**
* Returns term in current position
*
* @param Zend_Search_Lucene_Index_Term $term
* @return Zend_Search_Lucene_Index_Term|null
*/
public function currentTerm()
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/PriorityQueue.php';
require_once 'Zend/Search/Lucene/PriorityQueue.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_SegmentInfoPriorityQueue extends Zend_Search_Lucene_PriorityQueue
@@ -15,29 +15,29 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Index_SegmentInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfo.php';
require_once 'Zend/Search/Lucene/Index/SegmentInfo.php';
/** Zend_Search_Lucene_Index_SegmentWriter_StreamWriter */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentWriter/StreamWriter.php';
require_once 'Zend/Search/Lucene/Index/SegmentWriter/StreamWriter.php';
/** Zend_Search_Lucene_Index_SegmentInfoPriorityQueue */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php';
require_once 'Zend/Search/Lucene/Index/SegmentInfoPriorityQueue.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_SegmentMerger
@@ -232,7 +232,7 @@ class Zend_Search_Lucene_Index_SegmentMerger
$segmentStartId = 0;
foreach ($this->_segmentInfos as $segName => $segmentInfo) {
$segmentStartId = $segmentInfo->reset($segmentStartId, true);
$segmentStartId = $segmentInfo->reset($segmentStartId, Zend_Search_Lucene_Index_SegmentInfo::SM_MERGE_INFO);
// Skip "empty" segments
if ($segmentInfo->currentTerm() !== null) {
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Index_SegmentInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfo.php';
require_once 'Zend/Search/Lucene/Index/SegmentInfo.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Index_SegmentWriter
@@ -47,19 +47,33 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
*/
public static $indexInterval = 128;
/** Expert: The fraction of TermDocs entries stored in skip tables.
/**
* Expert: The fraction of TermDocs entries stored in skip tables.
* Larger values result in smaller indexes, greater acceleration, but fewer
* accelerable cases, while smaller values result in bigger indexes,
* less acceleration and more
* accelerable cases. More detailed experiments would be useful here.
*
* 0x0x7FFFFFFF indicates that we don't use skip data
* Default value is 16
* 0x7FFFFFFF indicates that we don't use skip data
*
* Note: not used in current implementation
*
* @var integer
*/
public static $skipInterval = 0x7FFFFFFF;
/**
* Expert: The maximum number of skip levels. Smaller values result in
* slightly smaller indexes, but slower skipping in big posting lists.
*
* 0 indicates that we don't use skip data
*
* Note: not used in current implementation
*
* @var integer
*/
public static $maxSkipLevels = 0;
/**
* Number of docs in a segment
*
@@ -245,6 +259,16 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
return $this->_docCount;
}
/**
* Return segment name
*
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* Dump Field Info (.fnm) segment file
*/
@@ -253,6 +277,12 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
$fnmFile = $this->_directory->createFile($this->_name . '.fnm');
$fnmFile->writeVInt(count($this->_fields));
$nrmFile = $this->_directory->createFile($this->_name . '.nrm');
// Write header
$nrmFile->writeBytes('NRM');
// Write format specifier
$nrmFile->writeByte((int)0xFF);
foreach ($this->_fields as $field) {
$fnmFile->writeString($field->name);
$fnmFile->writeByte(($field->isIndexed ? 0x01 : 0x00) |
@@ -262,14 +292,18 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
);
if ($field->isIndexed) {
$normFileName = $this->_name . '.f' . $field->number;
$fFile = $this->_directory->createFile($normFileName);
$fFile->writeBytes($this->_norms[$field->name]);
$this->_files[] = $normFileName;
// pre-2.1 index mode (not used now)
// $normFileName = $this->_name . '.f' . $field->number;
// $fFile = $this->_directory->createFile($normFileName);
// $fFile->writeBytes($this->_norms[$field->name]);
// $this->_files[] = $normFileName;
$nrmFile->writeBytes($this->_norms[$field->name]);
}
}
$this->_files[] = $this->_name . '.fnm';
$this->_files[] = $this->_name . '.nrm';
}
@@ -351,16 +385,18 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
public function initializeDictionaryFiles()
{
$this->_tisFile = $this->_directory->createFile($this->_name . '.tis');
$this->_tisFile->writeInt((int)0xFFFFFFFE);
$this->_tisFile->writeInt((int)0xFFFFFFFD);
$this->_tisFile->writeLong(0 /* dummy data for terms count */);
$this->_tisFile->writeInt(self::$indexInterval);
$this->_tisFile->writeInt(self::$skipInterval);
$this->_tisFile->writeInt(self::$maxSkipLevels);
$this->_tiiFile = $this->_directory->createFile($this->_name . '.tii');
$this->_tiiFile->writeInt((int)0xFFFFFFFE);
$this->_tiiFile->writeInt((int)0xFFFFFFFD);
$this->_tiiFile->writeLong(0 /* dummy data for terms count */);
$this->_tiiFile->writeInt(self::$indexInterval);
$this->_tiiFile->writeInt(self::$skipInterval);
$this->_tiiFile->writeInt(self::$maxSkipLevels);
/** Dump dictionary header */
$this->_tiiFile->writeVInt(0); // preffix length
@@ -370,7 +406,7 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
$this->_tiiFile->writeVInt(0); // DocFreq
$this->_tiiFile->writeVInt(0); // FreqDelta
$this->_tiiFile->writeVInt(0); // ProxDelta
$this->_tiiFile->writeVInt(20); // IndexDelta
$this->_tiiFile->writeVInt(24); // IndexDelta
$this->_frqFile = $this->_directory->createFile($this->_name . '.frq');
$this->_prxFile = $this->_directory->createFile($this->_name . '.prx');
@@ -384,7 +420,7 @@ abstract class Zend_Search_Lucene_Index_SegmentWriter
$this->_prevTermInfo = null;
$this->_prevIndexTerm = null;
$this->_prevIndexTermInfo = null;
$this->_lastIndexPosition = 20;
$this->_lastIndexPosition = 24;
$this->_termCount = 0;
}
@@ -15,26 +15,26 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Analysis_Analyzer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer.php';
/** Zend_Search_Lucene_Index_SegmentWriter */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentWriter.php';
require_once 'Zend/Search/Lucene/Index/SegmentWriter.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter extends Zend_Search_Lucene_Index_SegmentWriter
@@ -204,9 +204,12 @@ class Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter extends Zend_Search_
$this->_generateCFS();
return new Zend_Search_Lucene_Index_SegmentInfo($this->_name,
return new Zend_Search_Lucene_Index_SegmentInfo($this->_directory,
$this->_name,
$this->_docCount,
$this->_directory);
-1,
true,
true);
}
}
@@ -15,26 +15,26 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Index_SegmentInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfo.php';
require_once 'Zend/Search/Lucene/Index/SegmentInfo.php';
/** Zend_Search_Lucene_Index_SegmentWriter */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentWriter.php';
require_once 'Zend/Search/Lucene/Index/SegmentWriter.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_SegmentWriter_StreamWriter extends Zend_Search_Lucene_Index_SegmentWriter
@@ -86,9 +86,12 @@ class Zend_Search_Lucene_Index_SegmentWriter_StreamWriter extends Zend_Search_Lu
$this->_dumpFNM();
$this->_generateCFS();
return new Zend_Search_Lucene_Index_SegmentInfo($this->_name,
return new Zend_Search_Lucene_Index_SegmentInfo($this->_directory,
$this->_name,
$this->_docCount,
$this->_directory);
-1,
true,
true);
}
}
+37 -2
View File
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -31,7 +31,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_Term
@@ -74,6 +74,7 @@ class Zend_Search_Lucene_Index_Term
/**
* Get term prefix
*
* @param string $str
* @param integer $length
* @return string
*/
@@ -104,5 +105,39 @@ class Zend_Search_Lucene_Index_Term
return substr($str, 0, $prefixBytes);
}
/**
* Get UTF-8 string length
*
* @param string $str
* @return string
*/
public static function getLength($str)
{
$bytes = 0;
$chars = 0;
while ($bytes < strlen($str)) {
$charBytes = 1;
if ((ord($str[$bytes]) & 0xC0) == 0xC0) {
$charBytes++;
if (ord($str[$bytes]) & 0x20 ) {
$charBytes++;
if (ord($str[$bytes]) & 0x10 ) {
$charBytes++;
}
}
}
if ($bytes + $charBytes > strlen($str)) {
// wrong character
break;
}
$chars++;
$bytes += $charBytes;
}
return $chars;
}
}
+2 -2
View File
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -26,7 +26,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_TermInfo
+426 -159
View File
@@ -15,27 +15,33 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_SegmentWriter_ */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php';
/** Zend_Search_Lucene_Index_SegmentWriter_DocumentWriter */
require_once 'Zend/Search/Lucene/Index/SegmentWriter/DocumentWriter.php';
/** Zend_Search_Lucene_Index_SegmentInfo */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentInfo.php';
require_once 'Zend/Search/Lucene/Index/SegmentInfo.php';
/** Zend_Search_Lucene_Index_SegmentMerger */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/SegmentMerger.php';
require_once 'Zend/Search/Lucene/Index/SegmentMerger.php';
/** Zend_Search_Lucene_LockManager */
if (@$CFG->block_search_softlock){
require_once "Zend/Search/Lucene/SoftLockManager.php";
} else {
require_once "Zend/Search/Lucene/LockManager.php";
}
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Index
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Index_Writer
@@ -154,33 +160,29 @@ class Zend_Search_Lucene_Index_Writer
'.del' => '.del',
'.sti' => '.sti' );
/**
* Opens the index for writing
*
* IndexWriter constructor needs Directory as a parameter. It should be
* a string with a path to the index folder or a Directory object.
* Second constructor parameter create is optional - true to create the
* index or overwrite the existing one.
* Create empty index
*
* @param Zend_Search_Lucene_Storage_Directory $directory
* @param array $segmentInfos
* @param boolean $create
* @param integer $generation
* @param integer $nameCount
*/
public function __construct(Zend_Search_Lucene_Storage_Directory $directory, &$segmentInfos, $create = false)
public static function createIndex(Zend_Search_Lucene_Storage_Directory $directory, $generation, $nameCount)
{
$this->_directory = $directory;
$this->_segmentInfos = &$segmentInfos;
if ($generation == 0) {
// Create index in pre-2.1 mode
if ($create) {
foreach ($this->_directory->fileList() as $file) {
foreach ($directory->fileList() as $file) {
if ($file == 'deletable' ||
$file == 'segments' ||
isset(self::$_indexExtensions[ substr($file, strlen($file)-4)]) ||
preg_match('/\.f\d+$/i', $file) /* matches <segment_name>.f<decimal_nmber> file names */) {
$this->_directory->deleteFile($file);
$directory->deleteFile($file);
}
}
$segmentsFile = $this->_directory->createFile('segments');
$segmentsFile = $directory->createFile('segments');
$segmentsFile->writeInt((int)0xFFFFFFFF);
// write version (is initialized by current time
@@ -190,22 +192,55 @@ class Zend_Search_Lucene_Index_Writer
$segmentsFile->writeInt((int)($version & 0xFFFFFFFF));
// write name counter
$segmentsFile->writeInt(0);
$segmentsFile->writeInt($nameCount);
// write segment counter
$segmentsFile->writeInt(0);
$deletableFile = $this->_directory->createFile('deletable');
$deletableFile = $directory->createFile('deletable');
// write counter
$deletableFile->writeInt(0);
} else {
$segmentsFile = $this->_directory->getFileObject('segments');
$format = $segmentsFile->readInt();
if ($format != (int)0xFFFFFFFF) {
throw new Zend_Search_Lucene_Exception('Wrong segments file format');
}
$genFile = $directory->createFile('segments.gen');
$genFile->writeInt((int)0xFFFFFFFE);
// Write generation two times
$genFile->writeLong($generation);
$genFile->writeLong($generation);
$segmentsFile = $directory->createFile(Zend_Search_Lucene::getSegmentFileName($generation));
$segmentsFile->writeInt((int)0xFFFFFFFD);
// write version (is initialized by current time
// $segmentsFile->writeLong((int)microtime(true));
$version = microtime(true);
$segmentsFile->writeInt((int)($version/((double)0xFFFFFFFF + 1)));
$segmentsFile->writeInt((int)($version & 0xFFFFFFFF));
// write name counter
$segmentsFile->writeInt($nameCount);
// write segment counter
$segmentsFile->writeInt(0);
}
}
/**
* Open the index for writing
*
* IndexWriter constructor needs Directory as a parameter. It should be
* a string with a path to the index folder or a Directory object.
* Second constructor parameter create is optional - true to create the
* index or overwrite the existing one.
*
* @param Zend_Search_Lucene_Storage_Directory $directory
* @param array $segmentInfos
* @param Zend_Search_Lucene_Storage_File $cleanUpLock
*/
public function __construct(Zend_Search_Lucene_Storage_Directory $directory, &$segmentInfos)
{
$this->_directory = $directory;
$this->_segmentInfos = &$segmentInfos;
}
/**
* Adds a document to this index.
*
@@ -223,27 +258,86 @@ class Zend_Search_Lucene_Index_Writer
$this->commit();
}
$this->_versionUpdate++;
$this->_maybeMergeSegments();
$this->_versionUpdate++;
}
/**
* Merge segments if necessary
* Check if we have anything to merge
*
* @return boolean
*/
private function _maybeMergeSegments()
private function _hasAnythingToMerge()
{
$segmentSizes = array();
foreach ($this->_segmentInfos as $segId => $segmentInfo) {
$segmentSizes[$segId] = $segmentInfo->count();
foreach ($this->_segmentInfos as $segName => $segmentInfo) {
$segmentSizes[$segName] = $segmentInfo->count();
}
$mergePool = array();
$poolSize = 0;
$sizeToMerge = $this->maxBufferedDocs;
asort($segmentSizes, SORT_NUMERIC);
foreach ($segmentSizes as $segId => $size) {
foreach ($segmentSizes as $segName => $size) {
// Check, if segment comes into a new merging block
while ($size >= $sizeToMerge) {
// Merge previous block if it's large enough
if ($poolSize >= $sizeToMerge) {
return true;
}
$mergePool = array();
$poolSize = 0;
$sizeToMerge *= $this->mergeFactor;
if ($sizeToMerge > $this->maxMergeDocs) {
return false;
}
}
$mergePool[] = $this->_segmentInfos[$segName];
$poolSize += $size;
}
if ($poolSize >= $sizeToMerge) {
return true;
}
return false;
}
/**
* Merge segments if necessary
*/
private function _maybeMergeSegments()
{
if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) {
return;
}
if (!$this->_hasAnythingToMerge()) {
Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory);
return;
}
// Update segments list to be sure all segments are not merged yet by other process
$this->_updateSegments();
// Perform standard auto-optimization procedure
$segmentSizes = array();
foreach ($this->_segmentInfos as $segName => $segmentInfo) {
$segmentSizes[$segName] = $segmentInfo->count();
}
$mergePool = array();
$poolSize = 0;
$sizeToMerge = $this->maxBufferedDocs;
asort($segmentSizes, SORT_NUMERIC);
foreach ($segmentSizes as $segName => $size) {
// Check, if segment comes into a new merging block
while ($size >= $sizeToMerge) {
// Merge previous block if it's large enough
@@ -256,17 +350,20 @@ class Zend_Search_Lucene_Index_Writer
$sizeToMerge *= $this->mergeFactor;
if ($sizeToMerge > $this->maxMergeDocs) {
Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory);
return;
}
}
$mergePool[] = $this->_segmentInfos[$segId];
$mergePool[] = $this->_segmentInfos[$segName];
$poolSize += $size;
}
if ($poolSize >= $sizeToMerge) {
$this->_mergeSegments($mergePool);
}
Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory);
}
/**
@@ -278,13 +375,6 @@ class Zend_Search_Lucene_Index_Writer
*/
private function _mergeSegments($segments)
{
// Try to get exclusive non-blocking lock to the 'index.optimization.lock'
// Skip optimization if it's performed by other process right now
$optimizationLock = $this->_directory->createFile('index.optimization.lock');
if (!$optimizationLock->lock(LOCK_EX,true)) {
return;
}
$newName = $this->_newSegmentName();
$merger = new Zend_Search_Lucene_Index_SegmentMerger($this->_directory,
$newName);
@@ -299,9 +389,6 @@ class Zend_Search_Lucene_Index_Writer
}
$this->commit();
// optimization is finished
$optimizationLock->unlock();
}
/**
@@ -312,119 +399,299 @@ class Zend_Search_Lucene_Index_Writer
private function _updateSegments()
{
// Get an exclusive index lock
// Wait, until all parallel searchers or indexers won't stop
// and stop all next searchers, while we are updating segments file
$lock = $this->_directory->getFileObject('index.lock');
if (!$lock->lock(LOCK_EX)) {
throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock');
}
Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory);
$generation = Zend_Search_Lucene::getActualGeneration($this->_directory);
$segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false);
$newSegmentFile = $this->_directory->createFile(Zend_Search_Lucene::getSegmentFileName(++$generation), false);
// Do not share file handlers to get file updates from other sessions.
$segmentsFile = $this->_directory->getFileObject('segments', false);
$newSegmentFile = $this->_directory->createFile('segments.new', false);
// Write format marker
$newSegmentFile->writeInt((int)0xFFFFFFFF);
// Write index version
$segmentsFile->seek(4, SEEK_CUR);
// $version = $segmentsFile->readLong() + $this->_versionUpdate;
// Process version on 32-bit platforms
$versionHigh = $segmentsFile->readInt();
$versionLow = $segmentsFile->readInt();
$version = $versionHigh * ((double)0xFFFFFFFF + 1) +
(($versionLow < 0)? (double)0xFFFFFFFF - (-1 - $versionLow) : $versionLow);
$version += $this->_versionUpdate;
$this->_versionUpdate = 0;
$newSegmentFile->writeInt((int)($version/((double)0xFFFFFFFF + 1)));
$newSegmentFile->writeInt((int)($version & 0xFFFFFFFF));
// Write segment name counter
$newSegmentFile->writeInt($segmentsFile->readInt());
// Get number of segments offset
$numOfSegmentsOffset = $newSegmentFile->tell();
// Write number of segemnts
$segmentsCount = $segmentsFile->readInt();
$newSegmentFile->writeInt(0); // Write dummy data (segment counter)
$segments = array();
for ($count = 0; $count < $segmentsCount; $count++) {
$segName = $segmentsFile->readString();
$segSize = $segmentsFile->readInt();
if (!in_array($segName, $this->_segmentsToDelete)) {
$newSegmentFile->writeString($segName);
$newSegmentFile->writeInt($segSize);
$segments[$segName] = $segSize;
}
}
$segmentsFile->close();
$segmentsCount = count($segments) + count($this->_newSegments);
// Remove segments, not listed in $segments (deleted)
// Load segments, not listed in $this->_segmentInfos
foreach ($this->_segmentInfos as $segId => $segInfo) {
if (isset($segments[$segInfo->getName()])) {
// Segment is already included into $this->_segmentInfos
unset($segments[$segInfo->getName()]);
try {
$genFile = $this->_directory->getFileObject('segments.gen', false);
} catch (Zend_Search_Lucene_Exception $e) {
if (strpos($e->getMessage(), 'is not readable') !== false) {
$genFile = $this->_directory->createFile('segments.gen');
} else {
// remove deleted segment from a list
unset($this->_segmentInfos[$segId]);
throw $e;
}
}
// $segments contains a list of segments to load
// do it later
$genFile->writeInt((int)0xFFFFFFFE);
// Write generation (first copy)
$genFile->writeLong($generation);
foreach ($this->_newSegments as $segName => $segmentInfo) {
$newSegmentFile->writeString($segName);
$newSegmentFile->writeInt($segmentInfo->count());
try {
// Write format marker
$newSegmentFile->writeInt((int)0xFFFFFFFD);
// Skip format identifier
$segmentsFile->seek(4, SEEK_CUR);
// $version = $segmentsFile->readLong() + $this->_versionUpdate;
// Process version on 32-bit platforms
$versionHigh = $segmentsFile->readInt();
$versionLow = $segmentsFile->readInt();
$version = $versionHigh * ((double)0xFFFFFFFF + 1) +
(($versionLow < 0)? (double)0xFFFFFFFF - (-1 - $versionLow) : $versionLow);
$version += $this->_versionUpdate;
$this->_versionUpdate = 0;
$newSegmentFile->writeInt((int)($version/((double)0xFFFFFFFF + 1)));
$newSegmentFile->writeInt((int)($version & 0xFFFFFFFF));
// Write segment name counter
$newSegmentFile->writeInt($segmentsFile->readInt());
// Get number of segments offset
$numOfSegmentsOffset = $newSegmentFile->tell();
// Write dummy data (segment counter)
$newSegmentFile->writeInt(0);
// Read number of segemnts
$segmentsCount = $segmentsFile->readInt();
$this->_segmentInfos[] = $segmentInfo;
$segments = array();
for ($count = 0; $count < $segmentsCount; $count++) {
$segName = $segmentsFile->readString();
$segSize = $segmentsFile->readInt();
if ($generation == 1 /* retrieved generation is 0 */) {
// pre-2.1 index format
$delGenHigh = 0;
$delGenLow = 0;
$hasSingleNormFile = false;
$numField = (int)0xFFFFFFFF;
$isCompound = 1;
} else {
//$delGen = $segmentsFile->readLong();
$delGenHigh = $segmentsFile->readInt();
$delGenLow = $segmentsFile->readInt();
$hasSingleNormFile = $segmentsFile->readByte();
$numField = $segmentsFile->readInt();
$normGens = array();
if ($numField != (int)0xFFFFFFFF) {
for ($count1 = 0; $count1 < $numField; $count1++) {
$normGens[] = $segmentsFile->readLong();
}
}
$isCompound = $segmentsFile->readByte();
}
if (!in_array($segName, $this->_segmentsToDelete)) {
// Load segment if necessary
if (!isset($this->_segmentInfos[$segName])) {
$delGen = $delGenHigh * ((double)0xFFFFFFFF + 1) +
(($delGenLow < 0)? (double)0xFFFFFFFF - (-1 - $delGenLow) : $delGenLow);
$this->_segmentInfos[$segName] =
new Zend_Search_Lucene_Index_SegmentInfo($this->_directory,
$segName,
$segSize,
$delGen,
$hasSingleNormFile,
$isCompound);
} else {
// Retrieve actual detetions file generation number
$delGen = $this->_segmentInfos[$segName]->getDelGen();
if ($delGen >= 0) {
$delGenHigh = (int)($delGen/((double)0xFFFFFFFF + 1));
$delGenLow =(int)($delGen & 0xFFFFFFFF);
} else {
$delGenHigh = $delGenLow = (int)0xFFFFFFFF;
}
}
$newSegmentFile->writeString($segName);
$newSegmentFile->writeInt($segSize);
$newSegmentFile->writeInt($delGenHigh);
$newSegmentFile->writeInt($delGenLow);
$newSegmentFile->writeByte($hasSingleNormFile);
$newSegmentFile->writeInt($numField);
if ($numField != (int)0xFFFFFFFF) {
foreach ($normGens as $normGen) {
$newSegmentFile->writeLong($normGen);
}
}
$newSegmentFile->writeByte($isCompound);
$segments[$segName] = $segSize;
}
}
$segmentsFile->close();
$segmentsCount = count($segments) + count($this->_newSegments);
foreach ($this->_newSegments as $segName => $segmentInfo) {
$newSegmentFile->writeString($segName);
$newSegmentFile->writeInt($segmentInfo->count());
// delete file generation: -1 (there is no delete file yet)
$newSegmentFile->writeInt((int)0xFFFFFFFF);$newSegmentFile->writeInt((int)0xFFFFFFFF);
// HasSingleNormFile
$newSegmentFile->writeByte($segmentInfo->hasSingleNormFile());
// NumField
$newSegmentFile->writeInt((int)0xFFFFFFFF);
// IsCompoundFile
$newSegmentFile->writeByte($segmentInfo->isCompound());
$segments[$segmentInfo->getName()] = $segmentInfo->count();
$this->_segmentInfos[$segName] = $segmentInfo;
}
$this->_newSegments = array();
$newSegmentFile->seek($numOfSegmentsOffset);
$newSegmentFile->writeInt($segmentsCount); // Update segments count
$newSegmentFile->close();
} catch (Exception $e) {
/** Restore previous index generation */
$generation--;
$genFile->seek(4, SEEK_SET);
// Write generation number twice
$genFile->writeLong($generation); $genFile->writeLong($generation);
// Release index write lock
Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory);
// Throw the exception
throw $e;
}
$this->_newSegments = array();
$newSegmentFile->seek($numOfSegmentsOffset);
$newSegmentFile->writeInt($segmentsCount); // Update segments count
$newSegmentFile->close();
$this->_directory->renameFile('segments.new', 'segments');
// Write generation (second copy)
$genFile->writeLong($generation);
// Segments file update is finished
// Switch back to shared lock mode
$lock->lock(LOCK_SH);
$fileList = $this->_directory->fileList();
foreach ($this->_segmentsToDelete as $nameToDelete) {
foreach (self::$_indexExtensions as $ext) {
if ($this->_directory->fileExists($nameToDelete . $ext)) {
$this->_directory->deleteFile($nameToDelete . $ext);
// Check if another update process is not running now
// If yes, skip clean-up procedure
if (Zend_Search_Lucene_LockManager::escalateReadLock($this->_directory)) {
/**
* Clean-up directory
*/
$filesToDelete = array();
$filesTypes = array();
$filesNumbers = array();
// list of .del files of currently used segments
// each segment can have several generations of .del files
// only last should not be deleted
$delFiles = array();
foreach ($this->_directory->fileList() as $file) {
if ($file == 'deletable') {
// 'deletable' file
$filesToDelete[] = $file;
$filesTypes[] = 0; // delete this file first, since it's not used starting from Lucene v2.1
$filesNumbers[] = 0;
} else if ($file == 'segments') {
// 'segments' file
$filesToDelete[] = $file;
$filesTypes[] = 1; // second file to be deleted "zero" version of segments file (Lucene pre-2.1)
$filesNumbers[] = 0;
} else if (preg_match('/^segments_[a-zA-Z0-9]+$/i', $file)) {
// 'segments_xxx' file
// Check if it's not a just created generation file
if ($file != Zend_Search_Lucene::getSegmentFileName($generation)) {
$filesToDelete[] = $file;
$filesTypes[] = 2; // first group of files for deletions
$filesNumbers[] = (int)base_convert(substr($file, 9), 36, 10); // ordered by segment generation numbers
}
} else if (preg_match('/(^_([a-zA-Z0-9]+))\.f\d+$/i', $file, $matches)) {
// one of per segment files ('<segment_name>.f<decimal_number>')
// Check if it's not one of the segments in the current segments set
if (!isset($segments[$matches[1]])) {
$filesToDelete[] = $file;
$filesTypes[] = 3; // second group of files for deletions
$filesNumbers[] = (int)base_convert($matches[2], 36, 10); // order by segment number
}
} else if (preg_match('/(^_([a-zA-Z0-9]+))(_([a-zA-Z0-9]+))\.del$/i', $file, $matches)) {
// one of per segment files ('<segment_name>_<del_generation>.del' where <segment_name> is '_<segment_number>')
// Check if it's not one of the segments in the current segments set
if (!isset($segments[$matches[1]])) {
$filesToDelete[] = $file;
$filesTypes[] = 3; // second group of files for deletions
$filesNumbers[] = (int)base_convert($matches[2], 36, 10); // order by segment number
} else {
$segmentNumber = (int)base_convert($matches[2], 36, 10);
$delGeneration = (int)base_convert($matches[4], 36, 10);
if (!isset($delFiles[$segmentNumber])) {
$delFiles[$segmentNumber] = array();
}
$delFiles[$segmentNumber][$delGeneration] = $file;
}
} else if (isset(self::$_indexExtensions[substr($file, strlen($file)-4)])) {
// one of per segment files ('<segment_name>.<ext>')
$segmentName = substr($file, 0, strlen($file) - 4);
// Check if it's not one of the segments in the current segments set
if (!isset($segments[$segmentName]) &&
($this->_currentSegment === null || $this->_currentSegment->getName() != $segmentName)) {
$filesToDelete[] = $file;
$filesTypes[] = 3; // second group of files for deletions
$filesNumbers[] = (int)base_convert(substr($file, 1 /* skip '_' */, strlen($file)-5), 36, 10); // order by segment number
}
}
}
foreach ($fileList as $file) {
if (substr($file, 0, strlen($nameToDelete) + 2) == ($nameToDelete . '.f') &&
ctype_digit( substr($file, strlen($nameToDelete) + 2) )) {
$this->_directory->deleteFile($file);
$maxGenNumber = 0;
// process .del files of currently used segments
foreach ($delFiles as $segmentNumber => $segmentDelFiles) {
ksort($delFiles[$segmentNumber], SORT_NUMERIC);
array_pop($delFiles[$segmentNumber]); // remove last delete file generation from candidates for deleting
end($delFiles[$segmentNumber]);
$lastGenNumber = key($delFiles[$segmentNumber]);
if ($lastGenNumber > $maxGenNumber) {
$maxGenNumber = $lastGenNumber;
}
}
foreach ($delFiles as $segmentNumber => $segmentDelFiles) {
foreach ($segmentDelFiles as $delGeneration => $file) {
$filesToDelete[] = $file;
$filesTypes[] = 4; // third group of files for deletions
$filesNumbers[] = $segmentNumber*$maxGenNumber + $delGeneration; // order by <segment_number>,<del_generation> pair
}
}
// Reorder files for deleting
array_multisort($filesTypes, SORT_ASC, SORT_NUMERIC,
$filesNumbers, SORT_ASC, SORT_NUMERIC,
$filesToDelete, SORT_ASC, SORT_STRING);
foreach ($filesToDelete as $file) {
try {
$this->_directory->deleteFile($file);
} catch (Zend_Search_Lucene_Exception $e) {
if (strpos($e->getMessage(), 'Can\'t delete file') === false) {
// That's not "file is under processing or already deleted" exception
// Pass it through
throw $e;
}
}
}
// Return read lock into the previous state
Zend_Search_Lucene_LockManager::deEscalateReadLock($this->_directory);
} else {
// Only release resources if another index reader is running now
foreach ($this->_segmentsToDelete as $segName) {
foreach (self::$_indexExtensions as $ext) {
$this->_directory->purgeFile($segName . $ext);
}
}
}
$this->_segmentsToDelete = array();
// Load segments, created by other process
foreach ($segments as $segName => $segSize) {
// Load new segments
$this->_segmentInfos[] = new Zend_Search_Lucene_Index_SegmentInfo($segName,
$segSize,
$this->_directory);
// Clean-up _segmentsToDelete container
$this->_segmentsToDelete = array();
// Release index write lock
Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory);
// Remove unused segments from segments list
foreach ($this->_segmentInfos as $segName => $segmentInfo) {
if (!isset($segments[$segName])) {
unset($this->_segmentInfos[$segName]);
}
}
}
/**
* Commit current changes
*/
@@ -438,10 +705,7 @@ class Zend_Search_Lucene_Index_Writer
$this->_currentSegment = null;
}
if (count($this->_newSegments) != 0 ||
count($this->_segmentsToDelete) != 0) {
$this->_updateSegments();
}
$this->_updateSegments();
}
@@ -459,15 +723,24 @@ class Zend_Search_Lucene_Index_Writer
}
/**
* Merges all segments together into a single segment, optimizing
* an index for search.
* Input is an array of Zend_Search_Lucene_Index_SegmentInfo objects
* Merges all segments together into new one
*
* Returns true on success and false if another optimization or auto-optimization process
* is running now
*
* @throws Zend_Search_Lucene_Exception
* @return boolean
*/
public function optimize()
{
if (Zend_Search_Lucene_LockManager::obtainOptimizationLock($this->_directory) === false) {
return false;
}
$this->_mergeSegments($this->_segmentInfos);
Zend_Search_Lucene_LockManager::releaseOptimizationLock($this->_directory);
return true;
}
/**
@@ -477,16 +750,10 @@ class Zend_Search_Lucene_Index_Writer
*/
private function _newSegmentName()
{
// Do not share file handler to get file updates from other sessions.
$segmentsFile = $this->_directory->getFileObject('segments', false);
// Get exclusive segments file lock
// We have guarantee, that we will not intersect with _updateSegments() call
// of other process, because it needs exclusive index lock and waits
// until all other searchers won't stop
if (!$segmentsFile->lock(LOCK_EX)) {
throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock');
}
Zend_Search_Lucene_LockManager::obtainWriteLock($this->_directory);
$generation = Zend_Search_Lucene::getActualGeneration($this->_directory);
$segmentsFile = $this->_directory->getFileObject(Zend_Search_Lucene::getSegmentFileName($generation), false);
$segmentsFile->seek(12); // 12 = 4 (int, file format marker) + 8 (long, index version)
$segmentNameCounter = $segmentsFile->readInt();
@@ -498,8 +765,8 @@ class Zend_Search_Lucene_Index_Writer
// return (which calls $segmentsFile destructor)
$segmentsFile->flush();
$segmentsFile->unlock();
Zend_Search_Lucene_LockManager::releaseWriteLock($this->_directory);
return '_' . base_convert($segmentNameCounter, 10, 36);
}
+57 -2
View File
@@ -14,7 +14,7 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -22,7 +22,7 @@
/**
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
interface Zend_Search_Lucene_Interface
@@ -86,6 +86,24 @@ interface Zend_Search_Lucene_Interface
*/
public static function getDefaultSearchField();
/**
* Set result set limit.
*
* 0 (default) means no limit
*
* @param integer $limit
*/
public static function setResultSetLimit($limit);
/**
* Set result set limit.
*
* 0 means no limit
*
* @return integer
*/
public static function getResultSetLimit();
/**
* Retrieve index maxBufferedDocs option
*
@@ -306,6 +324,43 @@ interface Zend_Search_Lucene_Interface
*/
public function terms();
/**
* Reset terms stream.
*/
public function resetTermsStream();
/**
* Skip terms stream up to specified term preffix.
*
* Prefix contains fully specified field info and portion of searched term
*
* @param Zend_Search_Lucene_Index_Term $prefix
*/
public function skipTo(Zend_Search_Lucene_Index_Term $prefix);
/**
* Scans terms dictionary and returns next term
*
* @return Zend_Search_Lucene_Index_Term|null
*/
public function nextTerm();
/**
* Returns term in current position
*
* @return Zend_Search_Lucene_Index_Term|null
*/
public function currentTerm();
/**
* Close terms stream
*
* Should be used for resources clean up if stream is not read up to the end
*/
public function closeTermsStream();
/**
* Undeletes all documents currently marked as deleted in this index.
*/
+2 -2
View File
@@ -14,7 +14,7 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -31,7 +31,7 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_PriorityQueue
+79 -3
View File
@@ -14,12 +14,12 @@
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Interface */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Interface.php';
require_once 'Zend/Search/Lucene/Interface.php';
/**
@@ -29,7 +29,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Interface.php';
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Proxy implements Zend_Search_Lucene_Interface
@@ -144,6 +144,30 @@ class Zend_Search_Lucene_Proxy implements Zend_Search_Lucene_Interface
return Zend_Search_Lucene::getDefaultSearchField();
}
/**
* Set result set limit.
*
* 0 (default) means no limit
*
* @param integer $limit
*/
public static function setResultSetLimit($limit)
{
Zend_Search_Lucene::setResultSetLimit($limit);
}
/**
* Set result set limit.
*
* 0 means no limit
*
* @return integer
*/
public static function getResultSetLimit()
{
return Zend_Search_Lucene::getResultSetLimit();
}
/**
* Retrieve index maxBufferedDocs option
*
@@ -436,6 +460,58 @@ class Zend_Search_Lucene_Proxy implements Zend_Search_Lucene_Interface
return $this->_index->terms();
}
/**
* Reset terms stream.
*/
public function resetTermsStream()
{
$this->_index->resetTermsStream();
}
/**
* Skip terms stream up to specified term preffix.
*
* Prefix contains fully specified field info and portion of searched term
*
* @param Zend_Search_Lucene_Index_Term $prefix
*/
public function skipTo(Zend_Search_Lucene_Index_Term $prefix)
{
return $this->_index->skipTo($prefix);
}
/**
* Scans terms dictionary and returns next term
*
* @return Zend_Search_Lucene_Index_Term|null
*/
public function nextTerm()
{
return $this->_index->nextTerm();
}
/**
* Returns term in current position
*
* @return Zend_Search_Lucene_Index_Term|null
*/
public function currentTerm()
{
return $this->_index->currentTerm();
}
/**
* Close terms stream
*
* Should be used for resources clean up if stream is not read up to the end
*/
public function closeTermsStream()
{
$this->_index->closeTermsStream();
}
/**
* Undeletes all documents currently marked as deleted in this index.
*/
@@ -15,29 +15,29 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_FSM */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/FSM.php';
require_once 'Zend/Search/Lucene/FSM.php';
/** Zend_Search_Lucene_Search_QueryToken */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryToken.php';
require_once 'Zend/Search/Lucene/Search/QueryToken.php';
/** Zend_Search_Lucene_Search_QueryParser */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParser.php';
require_once 'Zend/Search/Lucene/Search/QueryParser.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_BooleanExpressionRecognizer extends Zend_Search_Lucene_FSM
+3 -3
View File
@@ -15,19 +15,19 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Document_Html */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Document/Html.php';
require_once 'Zend/Search/Lucene/Document/Html.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Search_Query
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Query */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query.php';
require_once 'Zend/Search/Lucene/Search/Query.php';
/** Zend_Search_Lucene_Search_Weight_Boolean */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight/Boolean.php';
require_once 'Zend/Search/Lucene/Search/Weight/Boolean.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_Query
@@ -39,7 +39,7 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
/**
* Subqueries
* Array of Zend_Search_Lucene_Query
* Array of Zend_Search_Lucene_Search_Query
*
* @var array
*/
@@ -105,7 +105,7 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
/**
* Add a $subquery (Zend_Search_Lucene_Query) to this query.
* Add a $subquery (Zend_Search_Lucene_Search_Query) to this query.
*
* The sign is specified as:
* TRUE - subquery is required
@@ -119,6 +119,7 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
public function addSubquery(Zend_Search_Lucene_Search_Query $subquery, $sign=null) {
if ($sign !== true || $this->_signs !== null) { // Skip, if all subqueries are required
if ($this->_signs === null) { // Check, If all previous subqueries are required
$this->_signs = array();
foreach ($this->_subqueries as $prevSubquery) {
$this->_signs[] = true;
}
@@ -165,6 +166,31 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
$signs[] = ($this->_signs === null)? true : $this->_signs[$id];
}
// Remove insignificant subqueries
foreach ($subqueries as $id => $subquery) {
if ($subquery instanceof Zend_Search_Lucene_Search_Query_Insignificant) {
// Insignificant subquery has to be removed anyway
unset($subqueries[$id]);
unset($signs[$id]);
}
}
if (count($subqueries) == 0) {
// Boolean query doesn't has non-insignificant subqueries
return new Zend_Search_Lucene_Search_Query_Insignificant();
}
// Check if all non-insignificant subqueries are prohibited
$allProhibited = true;
foreach ($signs as $sign) {
if ($sign !== false) {
$allProhibited = false;
break;
}
}
if ($allProhibited) {
return new Zend_Search_Lucene_Search_Query_Insignificant();
}
// Check for empty subqueries
foreach ($subqueries as $id => $subquery) {
if ($subquery instanceof Zend_Search_Lucene_Search_Query_Empty) {
@@ -180,6 +206,10 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
}
}
// Check, if reduced subqueries list is empty
if (count($subqueries) == 0) {
return new Zend_Search_Lucene_Search_Query_Empty();
}
// Check if all non-empty subqueries are prohibited
$allProhibited = true;
@@ -210,12 +240,6 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
}
// Check, if reduced subqueries list is empty
if (count($subqueries) == 0) {
return new Zend_Search_Lucene_Search_Query_Empty();
}
// Prepare first candidate for optimized query
$optimizedQuery = new Zend_Search_Lucene_Search_Query_Boolean($subqueries, $signs);
$optimizedQuery->setBoost($this->getBoost());
@@ -456,11 +480,35 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
$this->_resVector = array();
}
foreach ($this->_subqueries as $subquery) {
$resVectors = array();
$resVectorsSizes = array();
$resVectorsIds = array(); // is used to prevent arrays comparison
foreach ($this->_subqueries as $subqueryId => $subquery) {
$resVectors[] = $subquery->matchedDocs();
$resVectorsSizes[] = count(end($resVectors));
$resVectorsIds[] = $subqueryId;
}
// sort resvectors in order of subquery cardinality increasing
array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC,
$resVectorsIds, SORT_ASC, SORT_NUMERIC,
$resVectors);
foreach ($resVectors as $nextResVector) {
if($this->_resVector === null) {
$this->_resVector = $subquery->matchedDocs();
$this->_resVector = $nextResVector;
} else {
$this->_resVector = array_intersect_key($this->_resVector, $subquery->matchedDocs());
//$this->_resVector = array_intersect_key($this->_resVector, $nextResVector);
/**
* This code is used as workaround for array_intersect_key() slowness problem.
*/
$updatedVector = array();
foreach ($this->_resVector as $id => $value) {
if (isset($nextResVector[$id])) {
$updatedVector[$id] = $value;
}
}
$this->_resVector = $updatedVector;
}
if (count($this->_resVector) == 0) {
@@ -469,7 +517,8 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
}
}
ksort($this->_resVector, SORT_NUMERIC);
// ksort($this->_resVector, SORT_NUMERIC);
// Used algorithm doesn't change elements order
}
@@ -479,30 +528,61 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
*/
private function _calculateNonConjunctionResult()
{
$required = null;
$optional = array();
$requiredVectors = array();
$requiredVectorsSizes = array();
$requiredVectorsIds = array(); // is used to prevent arrays comparison
$optional = array();
foreach ($this->_subqueries as $subqueryId => $subquery) {
$docs = $subquery->matchedDocs();
if ($this->_signs[$subqueryId] === true) {
// required
if ($required !== null) {
// array intersection
$required = array_intersect_key($required, $docs);
} else {
$required = $docs;
}
$requiredVectors[] = $subquery->matchedDocs();
$requiredVectorsSizes[] = count(end($requiredVectors));
$requiredVectorsIds[] = $subqueryId;
} elseif ($this->_signs[$subqueryId] === false) {
// prohibited
// Do nothing. matchedDocs() may include non-matching id's
// Calculating prohibited vector may take significant time, but do not affect the result
// Skipped.
} else {
// neither required, nor prohibited
// array union
$optional += $docs;
$optional += $subquery->matchedDocs();
}
}
// sort resvectors in order of subquery cardinality increasing
array_multisort($requiredVectorsSizes, SORT_ASC, SORT_NUMERIC,
$requiredVectorsIds, SORT_ASC, SORT_NUMERIC,
$requiredVectors);
$required = null;
foreach ($requiredVectors as $nextResVector) {
if($required === null) {
$required = $nextResVector;
} else {
//$required = array_intersect_key($required, $nextResVector);
/**
* This code is used as workaround for array_intersect_key() slowness problem.
*/
$updatedVector = array();
foreach ($required as $id => $value) {
if (isset($nextResVector[$id])) {
$updatedVector[$id] = $value;
}
}
$required = $updatedVector;
}
if (count($required) == 0) {
// Empty result set, we don't need to check other terms
break;
}
}
if ($required !== null) {
$this->_resVector = &$required;
} else {
@@ -705,7 +785,7 @@ class Zend_Search_Lucene_Search_Query_Boolean extends Zend_Search_Lucene_Search_
$query .= '(' . $subquery->__toString() . ')';
if ($subquery->getBoost() != 1) {
$query .= '^' . $subquery->getBoost();
$query .= '^' . round($subquery->getBoost(), 4);
}
}
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Query */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query.php';
require_once 'Zend/Search/Lucene/Search/Query.php';
/** Zend_Search_Lucene_Search_Weight_Empty */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight/Empty.php';
require_once 'Zend/Search/Lucene/Search/Weight/Empty.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Query_Empty extends Zend_Search_Lucene_Search_Query
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Query */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query.php';
require_once 'Zend/Search/Lucene/Search/Query.php';
/** Zend_Search_Lucene_Search_Weight_MultiTerm */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight/MultiTerm.php';
require_once 'Zend/Search/Lucene/Search/Weight/MultiTerm.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Search_Query
@@ -103,7 +103,6 @@ class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Searc
*
* @param array $terms Array of Zend_Search_Lucene_Index_Term objects
* @param array $signs Array of signs. Sign is boolean|null.
* @return void
*/
public function __construct($terms = null, $signs = null)
{
@@ -139,6 +138,7 @@ class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Searc
public function addTerm(Zend_Search_Lucene_Index_Term $term, $sign = null) {
if ($sign !== true || $this->_signs !== null) { // Skip, if all terms are required
if ($this->_signs === null) { // Check, If all previous terms are required
$this->_signs = array();
foreach ($this->_terms as $prevTerm) {
$this->_signs[] = true;
}
@@ -316,22 +316,47 @@ class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Searc
$this->_resVector = array();
}
foreach( $this->_terms as $termId=>$term ) {
$resVectors = array();
$resVectorsSizes = array();
$resVectorsIds = array(); // is used to prevent arrays comparison
foreach ($this->_terms as $termId => $term) {
$resVectors[] = array_flip($reader->termDocs($term));
$resVectorsSizes[] = count(end($resVectors));
$resVectorsIds[] = $termId;
$this->_termsFreqs[$termId] = $reader->termFreqs($term);
}
// sort resvectors in order of subquery cardinality increasing
array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC,
$resVectorsIds, SORT_ASC, SORT_NUMERIC,
$resVectors);
foreach ($resVectors as $nextResVector) {
if($this->_resVector === null) {
$this->_resVector = array_flip($reader->termDocs($term));
$this->_resVector = $nextResVector;
} else {
$this->_resVector = array_intersect_key($this->_resVector, array_flip($reader->termDocs($term)));
//$this->_resVector = array_intersect_key($this->_resVector, $nextResVector);
/**
* This code is used as workaround for array_intersect_key() slowness problem.
*/
$updatedVector = array();
foreach ($this->_resVector as $id => $value) {
if (isset($nextResVector[$id])) {
$updatedVector[$id] = $value;
}
}
$this->_resVector = $updatedVector;
}
if (count($this->_resVector) == 0) {
// Empty result set, we don't need to check other terms
break;
}
$this->_termsFreqs[$termId] = $reader->termFreqs($term);
}
ksort($this->_resVector, SORT_NUMERIC);
// ksort($this->_resVector, SORT_NUMERIC);
// Docs are returned ordered. Used algorithm doesn't change elements order.
}
@@ -343,21 +368,21 @@ class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Searc
*/
private function _calculateNonConjunctionResult(Zend_Search_Lucene_Interface $reader)
{
$required = null;
$requiredVectors = array();
$requiredVectorsSizes = array();
$requiredVectorsIds = array(); // is used to prevent arrays comparison
$optional = array();
$prohibited = array();
foreach ($this->_terms as $termId => $term) {
$termDocs = array_flip($reader->termDocs($term));
if ($this->_signs[$termId] === true) {
// required
if ($required !== null) {
// array intersection
$required = array_intersect_key($required, $termDocs);
} else {
$required = $termDocs;
}
$requiredVectors[] = $termDocs;
$requiredVectorsSizes[] = count($termDocs);
$requiredVectorsIds[] = $termId;
} elseif ($this->_signs[$termId] === false) {
// prohibited
// array union
@@ -371,16 +396,65 @@ class Zend_Search_Lucene_Search_Query_MultiTerm extends Zend_Search_Lucene_Searc
$this->_termsFreqs[$termId] = $reader->termFreqs($term);
}
// sort resvectors in order of subquery cardinality increasing
array_multisort($requiredVectorsSizes, SORT_ASC, SORT_NUMERIC,
$requiredVectorsIds, SORT_ASC, SORT_NUMERIC,
$requiredVectors);
$required = null;
foreach ($requiredVectors as $nextResVector) {
if($required === null) {
$required = $nextResVector;
} else {
//$required = array_intersect_key($required, $nextResVector);
/**
* This code is used as workaround for array_intersect_key() slowness problem.
*/
$updatedVector = array();
foreach ($required as $id => $value) {
if (isset($nextResVector[$id])) {
$updatedVector[$id] = $value;
}
}
$required = $updatedVector;
}
if (count($required) == 0) {
// Empty result set, we don't need to check other terms
break;
}
}
if ($required !== null) {
$this->_resVector = (count($prohibited) > 0) ?
array_diff_key($required, $prohibited) :
$required;
$this->_resVector = $required;
} else {
$this->_resVector = (count($prohibited) > 0) ?
array_diff_key($optional, $prohibited) :
$optional;
$this->_resVector = $optional;
}
if (count($prohibited) != 0) {
// $this->_resVector = array_diff_key($this->_resVector, $prohibited);
/**
* This code is used as workaround for array_diff_key() slowness problem.
*/
if (count($this->_resVector) < count($prohibited)) {
$updatedVector = $this->_resVector;
foreach ($this->_resVector as $id => $value) {
if (isset($prohibited[$id])) {
unset($updatedVector[$id]);
}
}
$this->_resVector = $updatedVector;
} else {
$updatedVector = $this->_resVector;
foreach ($prohibited as $id => $value) {
unset($updatedVector[$id]);
}
$this->_resVector = $updatedVector;
}
}
ksort($this->_resVector, SORT_NUMERIC);
}
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -23,12 +23,12 @@
/**
* Zend_Search_Lucene_Search_Query
*/
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query.php';
require_once 'Zend/Search/Lucene/Search/Query.php';
/**
* Zend_Search_Lucene_Search_Weight_MultiTerm
*/
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight/Phrase.php';
require_once 'Zend/Search/Lucene/Search/Weight/Phrase.php';
/**
@@ -37,7 +37,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight/Phrase.php'
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Query_Phrase extends Zend_Search_Lucene_Search_Query
@@ -416,23 +416,48 @@ class Zend_Search_Lucene_Search_Query_Phrase extends Zend_Search_Lucene_Search_Q
$this->_resVector = array();
}
foreach( $this->_terms as $termId=>$term ) {
$resVectors = array();
$resVectorsSizes = array();
$resVectorsIds = array(); // is used to prevent arrays comparison
foreach ($this->_terms as $termId => $term) {
$resVectors[] = array_flip($reader->termDocs($term));
$resVectorsSizes[] = count(end($resVectors));
$resVectorsIds[] = $termId;
$this->_termsPositions[$termId] = $reader->termPositions($term);
}
// sort resvectors in order of subquery cardinality increasing
array_multisort($resVectorsSizes, SORT_ASC, SORT_NUMERIC,
$resVectorsIds, SORT_ASC, SORT_NUMERIC,
$resVectors);
foreach ($resVectors as $nextResVector) {
if($this->_resVector === null) {
$this->_resVector = array_flip($reader->termDocs($term));
$this->_resVector = $nextResVector;
} else {
$this->_resVector = array_intersect_key($this->_resVector, array_flip($reader->termDocs($term)));
//$this->_resVector = array_intersect_key($this->_resVector, $nextResVector);
/**
* This code is used as workaround for array_intersect_key() slowness problem.
*/
$updatedVector = array();
foreach ($this->_resVector as $id => $value) {
if (isset($nextResVector[$id])) {
$updatedVector[$id] = $value;
}
}
$this->_resVector = $updatedVector;
}
if (count($this->_resVector) == 0) {
// Empty result set, we don't need to check other terms
break;
}
$this->_termsPositions[$termId] = $reader->termPositions($term);
}
ksort($this->_resVector, SORT_NUMERIC);
// ksort($this->_resVector, SORT_NUMERIC);
// Docs are returned ordered. Used algorithm doesn't change elements order.
// Initialize weight if it's not done yet
$this->_initWeight($reader);
}
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Query */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query.php";
/** Zend_Search_Lucene_Search_Weight_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight/Term.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Weight/Term.php";
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Query_Term extends Zend_Search_Lucene_Search_Query
@@ -65,7 +65,7 @@ class Zend_Search_Lucene_Search_Query_Term extends Zend_Search_Lucene_Search_Que
* @param Zend_Search_Lucene_Index_Term $term
* @param boolean $sign
*/
public function __construct($term)
public function __construct(Zend_Search_Lucene_Index_Term $term)
{
$this->_term = $term;
}
@@ -15,36 +15,36 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once 'Zend/Search/Lucene/Index/Term.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Search_QueryEntry_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry/Term.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry/Term.php';
/** Zend_Search_Lucene_Search_QueryEntry_Phrase */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry/Phrase.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry/Phrase.php';
/** Zend_Search_Lucene_Search_QueryEntry_Subquery */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry/Subquery.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry/Subquery.php';
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Search_QueryEntry
@@ -15,25 +15,25 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once 'Zend/Search/Lucene/Index/Term.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Search_QueryEntry */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry.php';
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
/** Zend_Search_Lucene_Analysis_Analyzer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer.php';
@@ -41,7 +41,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryEntry_Phrase extends Zend_Search_Lucene_Search_QueryEntry
@@ -118,7 +118,7 @@ class Zend_Search_Lucene_Search_QueryEntry_Phrase extends Zend_Search_Lucene_Sea
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_phrase, $encoding);
if (count($tokens) == 0) {
return new Zend_Search_Lucene_Search_Query_Empty();
return new Zend_Search_Lucene_Search_Query_Insignificant();
}
if (count($tokens) == 1) {
@@ -130,10 +130,12 @@ class Zend_Search_Lucene_Search_QueryEntry_Phrase extends Zend_Search_Lucene_Sea
}
//It's not empty or one term query
$position = -1;
$query = new Zend_Search_Lucene_Search_Query_Phrase();
foreach ($tokens as $token) {
$position += $token->getPositionIncrement();
$term = new Zend_Search_Lucene_Index_Term($token->getTermText(), $this->_field);
$query->addTerm($term);
$query->addTerm($term, $position);
}
if ($this->_proximityQuery) {
@@ -15,29 +15,29 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once 'Zend/Search/Lucene/Index/Term.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Search_QueryEntry */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry.php';
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryEntry_Subquery extends Zend_Search_Lucene_Search_QueryEntry
@@ -15,25 +15,25 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once 'Zend/Search/Lucene/Index/Term.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Search_QueryEntry */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry.php';
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
/** Zend_Search_Lucene_Analysis_Analyzer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
require_once 'Zend/Search/Lucene/Analysis/Analyzer.php';
@@ -41,7 +41,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Analysis/Analyzer.php';
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryEntry_Term extends Zend_Search_Lucene_Search_QueryEntry
@@ -100,7 +100,7 @@ class Zend_Search_Lucene_Search_QueryEntry_Term extends Zend_Search_Lucene_Searc
if ($parameter !== null) {
$this->_similarity = $parameter;
} else {
$this->_similarity = 0.5;
$this->_similarity = Zend_Search_Lucene_Search_Query_Fuzzy::DEFAULT_MIN_SIMILARITY;
}
}
@@ -113,28 +113,77 @@ class Zend_Search_Lucene_Search_QueryEntry_Term extends Zend_Search_Lucene_Searc
*/
public function getQuery($encoding)
{
if ($this->_fuzzyQuery) {
throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search is not supported yet.');
}
if (strpos($this->_term, '?') !== false || strpos($this->_term, '*') !== false) {
throw new Zend_Search_Lucene_Search_QueryParserException('Wildcard queries are not supported yet.');
if ($this->_fuzzyQuery) {
throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search is not supported for terms with wildcards.');
}
$pattern = '';
$subPatterns = explode('*', $this->_term);
$astericFirstPass = true;
foreach ($subPatterns as $subPattern) {
if (!$astericFirstPass) {
$pattern .= '*';
} else {
$astericFirstPass = false;
}
$subPatternsL2 = explode('?', $subPattern);
$qMarkFirstPass = true;
foreach ($subPatternsL2 as $subPatternL2) {
if (!$qMarkFirstPass) {
$pattern .= '?';
} else {
$qMarkFirstPass = false;
}
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($subPatternL2, $encoding);
if (count($tokens) > 1) {
throw new Zend_Search_Lucene_Search_QueryParserException('Wildcard search is supported only for non-multiple word terms');
}
foreach ($tokens as $token) {
$pattern .= $token->getTermText();
}
}
}
$term = new Zend_Search_Lucene_Index_Term($pattern, $this->_field);
$query = new Zend_Search_Lucene_Search_Query_Wildcard($term);
$query->setBoost($this->_boost);
return $query;
}
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_term, $encoding);
if (count($tokens) == 0) {
return new Zend_Search_Lucene_Search_Query_Empty();
return new Zend_Search_Lucene_Search_Query_Insignificant();
}
if (count($tokens) == 1) {
$term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);
if (count($tokens) == 1 && !$this->_fuzzyQuery) {
$term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);
$query = new Zend_Search_Lucene_Search_Query_Term($term);
$query->setBoost($this->_boost);
return $query;
}
if (count($tokens) == 1 && $this->_fuzzyQuery) {
$term = new Zend_Search_Lucene_Index_Term($tokens[0]->getTermText(), $this->_field);
$query = new Zend_Search_Lucene_Search_Query_Fuzzy($term, $this->_similarity);
$query->setBoost($this->_boost);
return $query;
}
if ($this->_fuzzyQuery) {
throw new Zend_Search_Lucene_Search_QueryParserException('Fuzzy search is supported only for non-multiple word terms');
}
//It's not empty or one term query
$query = new Zend_Search_Lucene_Search_Query_MultiTerm();
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -24,7 +24,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryHit
@@ -15,29 +15,29 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_FSM */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/FSM.php';
require_once 'Zend/Search/Lucene/FSM.php';
/** Zend_Search_Lucene_Search_QueryParser */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryToken.php';
require_once 'Zend/Search/Lucene/Search/QueryToken.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryLexer extends Zend_Search_Lucene_FSM
+184 -75
View File
@@ -15,52 +15,64 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Index/Term.php";
/** Zend_Search_Lucene_Search_Query_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Term.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Term.php";
/** Zend_Search_Lucene_Search_Query_MultiTerm */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/MultiTerm.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/MultiTerm.php";
/** Zend_Search_Lucene_Search_Query_Boolean */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Boolean.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Boolean.php";
/** Zend_Search_Lucene_Search_Query_Phrase */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Phrase.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Phrase.php";
/** Zend_Search_Lucene_Search_Query_Wildcard */
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Wildcard.php";
/** Zend_Search_Lucene_Search_Query_Range */
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Range.php";
/** Zend_Search_Lucene_Search_Query_Fuzzy */
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Fuzzy.php";
/** Zend_Search_Lucene_Search_Query_Empty */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Empty.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Empty.php";
/** Zend_Search_Lucene_Search_Query_Insignificant */
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/Query/Insignificant.php";
/** Zend_Search_Lucene_Search_QueryLexer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryLexer.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/QueryLexer.php";
/** Zend_Search_Lucene_Search_QueryParserContext */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserContext.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/QueryParserContext.php";
/** Zend_Search_Lucene_FSM */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/FSM.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/FSM.php";
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Exception.php";
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once "{$CFG->dirroot}/search/Zend/Search/Lucene/Search/QueryParserException.php";
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
@@ -139,6 +151,26 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
private $_defaultEncoding = '';
/**
* Defines query parsing mode.
*
* If this option is turned on, then query parser suppress query parser exceptions
* and constructs multi-term query using all words from a query.
*
* That helps to avoid exceptions caused by queries, which don't conform to query language,
* but limits possibilities to check, that query entered by user has some inconsistencies.
*
*
* Default is true.
*
* Use {@link Zend_Search_Lucene::suppressQueryParsingExceptions()},
* {@link Zend_Search_Lucene::dontSuppressQueryParsingExceptions()} and
* {@link Zend_Search_Lucene::checkQueryParsingExceptionsSuppressMode()} to operate
* with this setting.
*
* @var boolean
*/
private $_suppressQueryParsingExceptions = true;
/**
* Boolean operators constants
@@ -256,6 +288,18 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
$this->_lexer = new Zend_Search_Lucene_Search_QueryLexer();
}
/**
* Get query parser instance
*
* @return Zend_Search_Lucene_Search_QueryParser
*/
private static function _getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Set query string default encoding
@@ -264,11 +308,7 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public static function setDefaultEncoding($encoding)
{
if (self::$_instance === null) {
self::$_instance = new Zend_Search_Lucene_Search_QueryParser();
}
self::$_instance->_defaultEncoding = $encoding;
self::_getInstance()->_defaultEncoding = $encoding;
}
/**
@@ -278,11 +318,7 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public static function getDefaultEncoding()
{
if (self::$_instance === null) {
self::$_instance = new Zend_Search_Lucene_Search_QueryParser();
}
return self::$_instance->_defaultEncoding;
return self::_getInstance()->_defaultEncoding;
}
/**
@@ -292,11 +328,7 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public static function setDefaultOperator($operator)
{
if (self::$_instance === null) {
self::$_instance = new Zend_Search_Lucene_Search_QueryParser();
}
self::$_instance->_defaultOperator = $operator;
self::_getInstance()->_defaultOperator = $operator;
}
/**
@@ -306,13 +338,34 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public static function getDefaultOperator()
{
if (self::$_instance === null) {
self::$_instance = new Zend_Search_Lucene_Search_QueryParser();
}
return self::$_instance->_defaultOperator;
return self::_getInstance()->_defaultOperator;
}
/**
* Turn on 'suppress query parser exceptions' mode.
*/
public static function suppressQueryParsingExceptions()
{
self::_getInstance()->_suppressQueryParsingExceptions = true;
}
/**
* Turn off 'suppress query parser exceptions' mode.
*/
public static function dontSuppressQueryParsingExceptions()
{
self::_getInstance()->_suppressQueryParsingExceptions = false;
}
/**
* Check 'suppress query parser exceptions' mode.
* @return boolean
*/
public static function queryParsingExceptionsSuppressed()
{
return self::_getInstance()->_suppressQueryParsingExceptions;
}
/**
* Parses a query string
*
@@ -323,42 +376,62 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public static function parse($strQuery, $encoding = null)
{
if (self::$_instance === null) {
self::$_instance = new Zend_Search_Lucene_Search_QueryParser();
}
self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding;
self::$_instance->_lastToken = null;
self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding);
self::$_instance->_contextStack = array();
self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding);
// Empty query
if (count(self::$_instance->_tokens) == 0) {
return new Zend_Search_Lucene_Search_Query_Empty();
}
foreach (self::$_instance->_tokens as $token) {
try {
self::$_instance->_currentToken = $token;
self::$_instance->process($token->type);
self::$_instance->_lastToken = $token;
} catch (Exception $e) {
if (strpos($e->getMessage(), 'There is no any rule for') !== false) {
throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.' );
self::_getInstance();
// Reset FSM if previous parse operation didn't return it into a correct state
self::$_instance->reset();
try {
self::$_instance->_encoding = ($encoding !== null) ? $encoding : self::$_instance->_defaultEncoding;
self::$_instance->_lastToken = null;
self::$_instance->_context = new Zend_Search_Lucene_Search_QueryParserContext(self::$_instance->_encoding);
self::$_instance->_contextStack = array();
self::$_instance->_tokens = self::$_instance->_lexer->tokenize($strQuery, self::$_instance->_encoding);
// Empty query
if (count(self::$_instance->_tokens) == 0) {
return new Zend_Search_Lucene_Search_Query_Insignificant();
}
foreach (self::$_instance->_tokens as $token) {
try {
self::$_instance->_currentToken = $token;
self::$_instance->process($token->type);
self::$_instance->_lastToken = $token;
} catch (Exception $e) {
if (strpos($e->getMessage(), 'There is no any rule for') !== false) {
throw new Zend_Search_Lucene_Search_QueryParserException( 'Syntax error at char position ' . $token->position . '.' );
}
throw $e;
}
}
if (count(self::$_instance->_contextStack) != 0) {
throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' );
}
return self::$_instance->_context->getQuery();
} catch (Zend_Search_Lucene_Search_QueryParserException $e) {
if (self::$_instance->_suppressQueryParsingExceptions) {
$queryTokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($strQuery, self::$_instance->_encoding);
$query = new Zend_Search_Lucene_Search_Query_MultiTerm();
$termsSign = (self::$_instance->_defaultOperator == self::B_AND) ? true /* required term */ :
null /* optional term */;
foreach ($queryTokens as $token) {
$query->addTerm(new Zend_Search_Lucene_Index_Term($token->getTermText()), $termsSign);
}
return $query;
} else {
throw $e;
}
}
if (count(self::$_instance->_contextStack) != 0) {
throw new Zend_Search_Lucene_Search_QueryParserException('Syntax Error: mismatched parentheses, every opening must have closing.' );
}
return self::$_instance->_context->getQuery();
}
@@ -433,7 +506,7 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
default:
// It's not a user input exception
throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position .' );
throw new Zend_Search_Lucene_Exception('Lexeme modifier parameter must follow lexeme modifier. Char position 0.' );
}
}
@@ -485,13 +558,31 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public function openedRQLastTerm()
{
throw new Zend_Search_Lucene_Search_QueryParserException('Range queries are not supported yet.');
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding);
if (count($tokens) > 1) {
throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
} else if (count($tokens) == 1) {
$from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
} else {
$from = null;
}
// $firstTerm = new Zend_Search_Lucene_Index_Term($this->_rqFirstTerm, $this->_context->getField());
// $lastTerm = new Zend_Search_Lucene_Index_Term($this->_currentToken->text, $this->_context->getField());
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding);
if (count($tokens) > 1) {
throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
} else if (count($tokens) == 1) {
$to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
} else {
$to = null;
}
// $query = new Zend_Search_Lucene_Search_Query_Range($firstTerm, $lastTerm, false);
// $this->_context->addentry($query);
if ($from === null && $to === null) {
throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term');
}
$rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, false);
$entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery);
$this->_context->addEntry($entry);
}
/**
@@ -509,13 +600,31 @@ class Zend_Search_Lucene_Search_QueryParser extends Zend_Search_Lucene_FSM
*/
public function closedRQLastTerm()
{
throw new Zend_Search_Lucene_Search_QueryParserException('Range queries are not supported yet.');
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_rqFirstTerm, $this->_encoding);
if (count($tokens) > 1) {
throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
} else if (count($tokens) == 1) {
$from = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
} else {
$from = null;
}
// $firstTerm = new Zend_Search_Lucene_Index_Term($this->_rqFirstTerm, $this->_context->getField());
// $lastTerm = new Zend_Search_Lucene_Index_Term($this->_currentToken->text, $this->_context->getField());
$tokens = Zend_Search_Lucene_Analysis_Analyzer::getDefault()->tokenize($this->_currentToken->text, $this->_encoding);
if (count($tokens) > 1) {
throw new Zend_Search_Lucene_Search_QueryParserException('Range query boundary terms must be non-multiple word terms');
} else if (count($tokens) == 1) {
$to = new Zend_Search_Lucene_Index_Term(reset($tokens)->getTermText(), $this->_context->getField());
} else {
$to = null;
}
// $query = new Zend_Search_Lucene_Search_Query_Range($firstTerm, $lastTerm, true);
// $this->_context->addentry($query);
if ($from === null && $to === null) {
throw new Zend_Search_Lucene_Search_QueryParserException('At least one range query boundary term must be non-empty term');
}
$rangeQuery = new Zend_Search_Lucene_Search_Query_Range($from, $to, true);
$entry = new Zend_Search_Lucene_Search_QueryEntry_Subquery($rangeQuery);
$this->_context->addEntry($entry);
}
}
@@ -15,50 +15,50 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_FSM */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/FSM.php';
require_once 'Zend/Search/Lucene/FSM.php';
/** Zend_Search_Lucene_Index_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Index/Term.php';
require_once 'Zend/Search/Lucene/Index/Term.php';
/** Zend_Search_Lucene_Search_QueryToken */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryToken.php';
require_once 'Zend/Search/Lucene/Search/QueryToken.php';
/** Zend_Search_Lucene_Search_Query_Term */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Term.php';
require_once 'Zend/Search/Lucene/Search/Query/Term.php';
/** Zend_Search_Lucene_Search_Query_MultiTerm */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/MultiTerm.php';
require_once 'Zend/Search/Lucene/Search/Query/MultiTerm.php';
/** Zend_Search_Lucene_Search_Query_Boolean */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Boolean.php';
require_once 'Zend/Search/Lucene/Search/Query/Boolean.php';
/** Zend_Search_Lucene_Search_Query_Phrase */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Query/Phrase.php';
require_once 'Zend/Search/Lucene/Search/Query/Phrase.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Search_QueryParserException */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryParserException.php';
require_once 'Zend/Search/Lucene/Search/QueryParserException.php';
/** Zend_Search_Lucene_Search_BooleanExpressionRecognizer */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php';
require_once 'Zend/Search/Lucene/Search/BooleanExpressionRecognizer.php';
/** Zend_Search_Lucene_Search_QueryEntry */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/QueryEntry.php';
require_once 'Zend/Search/Lucene/Search/QueryEntry.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryParserContext
@@ -360,7 +360,7 @@ class Zend_Search_Lucene_Search_QueryParserContext
}
if (!$nonNegativeEntryFound) {
unset($conjuctions[$conjuctionId]);
unset($conjuctions[$conjuctionId]);
}
}
@@ -382,7 +382,7 @@ class Zend_Search_Lucene_Search_QueryParserContext
}
if (count($subqueries) == 0) {
return new Zend_Search_Lucene_Search_Query_Empty();
return new Zend_Search_Lucene_Search_Query_Insignificant();
}
if (count($subqueries) == 1) {
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -23,14 +23,14 @@
/**
* Zend_Search_Lucene base exception
*/
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
* Special exception type, which may be used to intercept wrong user input
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_QueryToken
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Similarity_Default */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Similarity/Default.php';
require_once 'Zend/Search/Lucene/Search/Similarity/Default.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Search_Similarity
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Similarity */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Similarity.php';
require_once 'Zend/Search/Lucene/Search/Similarity.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Similarity_Default extends Zend_Search_Lucene_Search_Similarity
@@ -38,7 +38,7 @@ class Zend_Search_Lucene_Search_Similarity_Default extends Zend_Search_Lucene_Se
* Implemented as '1/sqrt(numTerms)'.
*
* @param string $fieldName
* @param integer numTerms
* @param integer $numTerms
* @return float
*/
public function lengthNorm($fieldName, $numTerms)
+2 -2
View File
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -32,7 +32,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Search_Weight
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Weight */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight.php';
require_once 'Zend/Search/Lucene/Search/Weight.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Weight_Boolean extends Zend_Search_Lucene_Search_Weight
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Weight */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight.php';
require_once 'Zend/Search/Lucene/Search/Weight.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Weight_Empty extends Zend_Search_Lucene_Search_Weight
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Weight */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight.php';
require_once 'Zend/Search/Lucene/Search/Weight.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Weight_MultiTerm extends Zend_Search_Lucene_Search_Weight
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -23,14 +23,14 @@
/**
* Zend_Search_Lucene_Search_Weight
*/
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight.php';
require_once 'Zend/Search/Lucene/Search/Weight.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Weight_Phrase extends Zend_Search_Lucene_Search_Weight
@@ -15,20 +15,20 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Search_Weight */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Search/Weight.php';
require_once 'Zend/Search/Lucene/Search/Weight.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Search
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Search_Weight_Term extends Zend_Search_Lucene_Search_Weight
@@ -0,0 +1,225 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once 'Zend/Search/Lucene/Exception.php';
/** Zend_Search_Lucene_Storage_Directory */
require_once 'Zend/Search/Lucene/Storage/Directory.php';
/** Zend_Search_Lucene_Storage_File */
require_once 'Zend/Search/Lucene/Storage/File.php';
/**
* This is an utility class which provides index locks processing functionality
*
* @category Zend
* @package Zend_Search_Lucene
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_LockManager
{
const WRITE_LOCK_FILE = 'write.lock.file';
const READ_LOCK_FILE = 'read.lock.file';
const EXCLUSIVE_READ_LOCK_FILE = 'exread.lock.file';
const OPTIMIZATION_LOCK_FILE = 'optimization.lock.file';
/**
* Obtain exclusive write lock on the index
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
* @return Zend_Search_Lucene_Storage_File
* @throws Zend_Search_Lucene_Exception
*/
public static function obtainWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
if ($lockDirectory->fileExists(self::WRITE_LOCK_FILE)){
throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock : somebody else is writing');
}
try {
$lock = $lockDirectory->createFile(self::WRITE_LOCK_FILE);
return $lock;
}
catch(Zend_Search_Lucene_Exception $e) {
throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock');
}
return null;
}
/**
* Release exclusive write lock
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
*/
public static function releaseWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
$lockDirectory->deleteFile(self::WRITE_LOCK_FILE);
}
/**
* Obtain shared read lock on the index
*
* It doesn't block other read or update processes, but prevent index from the premature cleaning-up
*
* @param Zend_Search_Lucene_Storage_Directory $defaultLockDirectory
* @return Zend_Search_Lucene_Storage_File
* @throws Zend_Search_Lucene_Exception
*/
public static function obtainReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
// is being written. Can't read
if ($lockDirectory->fileExists(self::WRITE_LOCK_FILE)){
throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock : write in progress');
}
if ($lockDirectory->fileExists(self::EXCLUSIVE_READ_LOCK_FILE)){
throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock : read lock operation in progress');
} else {
$lock = $lockDirectory->createFile(self::EXCLUSIVE_READ_LOCK_FILE);
}
try {
if (!$lockDirectory->fileExists(self::READ_LOCK_FILE)){
$accesscount = 0;
} else {
// get the existing lock file
$lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE, false);
$accesscount = $lock->readBytes($lock->size());
$lock->close();
$lockDirectory->deleteFile(self::READ_LOCK_FILE);
}
// raise the access counter
$accesscount++;
// store the access counter
$lock = $lockDirectory->createFile(self::READ_LOCK_FILE);
$lock->writeBytes($accesscount);
$lock->flush();
$lock->close();
}
catch (Zend_Search_Lucene_Exception $e) {
$lockDirectory->deleteFile(self::EXCLUSIVE_READ_LOCK_FILE);
print_object($e);
throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock');
}
$lockDirectory->deleteFile(self::EXCLUSIVE_READ_LOCK_FILE);
return $lock;
}
/**
* Release shared read lock
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
*/
public static function releaseReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
// get exclusive operation lock on read lock file.
if ($lockDirectory->fileExists(self::EXCLUSIVE_READ_LOCK_FILE)){
throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock : read lock operation in progress');
} else {
$lock = $lockDirectory->createFile(self::EXCLUSIVE_READ_LOCK_FILE);
}
try {
$lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE, false);
$accesscounter = $lock->readBytes($lock->size());
$lock->close();
$accesscounter--;
$lockDirectory->deleteFile(self::READ_LOCK_FILE);
if ($accesscounter > 1){ // we have'nt released all locks. Create the file again.
$lock = $lockDirectory->createFile(self::READ_LOCK_FILE);
$lock->writeBytes($accesscount);
$lock->flush();
$lock->close();
}
}
catch(Zend_Search_Lucene_Exception $e){
$lockDirectory->deleteFile(self::EXCLUSIVE_READ_LOCK_FILE);
// accept failover here
// throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock');
}
$lockDirectory->deleteFile(self::EXCLUSIVE_READ_LOCK_FILE);
}
/**
* Escalate Read lock to exclusive level
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
* @return boolean
*/
public static function escalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
// get exclusive operation lock on read lock file.
if ($lockDirectory->fileExists(self::EXCLUSIVE_READ_LOCK_FILE)){
return false;
} else {
$lock = $lockDirectory->createFile(self::EXCLUSIVE_READ_LOCK_FILE);
return true;
}
}
/**
* De-escalate Read lock to shared level
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
*/
public static function deEscalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
$lockDirectory->deleteFile(self::EXCLUSIVE_READ_LOCK_FILE);
}
/**
* Obtain exclusive optimization lock on the index
*
* Returns lock object on success and false otherwise (doesn't block execution)
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
* @return mixed
*/
public static function obtainOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
if ($lockDirectory->fileExists(self::OPTIMIZATION_LOCK_FILE)){
return false;
}
$lock = $lockDirectory->createFile(self::OPTIMIZATION_LOCK_FILE);
return $lock;
}
/**
* Release exclusive optimization lock
*
* @param Zend_Search_Lucene_Storage_Directory $lockDirectory
*/
public static function releaseOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory)
{
$lockDirectory->deleteFile(self::OPTIMIZATION_LOCK_FILE);
}
}
@@ -15,7 +15,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
@@ -24,7 +24,7 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Storage_Directory
@@ -61,7 +61,16 @@ abstract class Zend_Search_Lucene_Storage_Directory
*/
abstract public function deleteFile($filename);
/**
* Purge file if it's cached by directory object
*
* Method is used to prevent 'too many open files' error
*
* @param string $filename
* @return void
*/
abstract public function purgeFile($filename);
/**
* Returns true if a file with the given $filename exists.
*
@@ -15,16 +15,16 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Storage_Directory */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/Directory.php';
require_once 'Zend/Search/Lucene/Storage/Directory.php';
/** Zend_Search_Lucene_Storage_File_Filesystem */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/File/Filesystem.php';
require_once 'Zend/Search/Lucene/Storage/File/Filesystem.php';
/**
@@ -33,7 +33,7 @@ require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/File/Filesystem.p
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene_Storage_Directory
@@ -43,7 +43,7 @@ class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene
*
* @var string
*/
private $_dirPath = null;
protected $_dirPath = null;
/**
* Cache for Zend_Search_Lucene_Storage_File_Filesystem objects
@@ -52,7 +52,35 @@ class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene
* @var array
* @throws Zend_Search_Lucene_Exception
*/
private $_fileHandlers;
protected $_fileHandlers;
/**
* Default file permissions
*
* @var integer
*/
protected static $_defaultFilePermissions = 0666;
/**
* Get default file permissions
*
* @return integer
*/
public static function getDefaultFilePermissions()
{
return self::$_defaultFilePermissions;
}
/**
* Set default file permissions
*
* @param integer $mode
*/
public static function setDefaultFilePermissions($mode)
{
self::$_defaultFilePermissions = $mode;
}
/**
@@ -144,6 +172,7 @@ class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene
*
* @param string $filename
* @return Zend_Search_Lucene_Storage_File
* @throws Zend_Search_Lucene_Exception
*/
public function createFile($filename)
{
@@ -152,6 +181,16 @@ class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene
}
unset($this->_fileHandlers[$filename]);
$this->_fileHandlers[$filename] = new Zend_Search_Lucene_Storage_File_Filesystem($this->_dirPath . '/' . $filename, 'w+b');
global $php_errormsg;
$trackErrors = ini_get('track_errors');
ini_set('track_errors', '1');
if (!@chmod($this->_dirPath . '/' . $filename, self::$_defaultFilePermissions)) {
ini_set('track_errors', $trackErrors);
throw new Zend_Search_Lucene_Exception($php_errormsg);
}
ini_set('track_errors', $trackErrors);
return $this->_fileHandlers[$filename];
}
@@ -161,22 +200,42 @@ class Zend_Search_Lucene_Storage_Directory_Filesystem extends Zend_Search_Lucene
*
* @param string $filename
* @return void
* @throws Zend_Search_Lucene_Exception
*/
public function deleteFile($filename)
{
/**
* @todo add support of "deletable" file
* "deletable" is used on Windows systems if file can't be deleted
* (while it is still open).
*/
if (isset($this->_fileHandlers[$filename])) {
$this->_fileHandlers[$filename]->close();
}
unset($this->_fileHandlers[$filename]);
unlink($this->_dirPath . '/' . $filename);
global $php_errormsg;
$trackErrors = ini_get('track_errors'); ini_set('track_errors', '1');
if (!@unlink($this->_dirPath . '/' . $filename)) {
ini_set('track_errors', $trackErrors);
// keep loose on failed deletion.
// throw new Zend_Search_Lucene_Exception('Can\'t delete file: ' . $php_errormsg);
}
ini_set('track_errors', $trackErrors);
}
/**
* Purge file if it's cached by directory object
*
* Method is used to prevent 'too many open files' error
*
* @param string $filename
* @return void
*/
public function purgeFile($filename)
{
if (isset($this->_fileHandlers[$filename])) {
$this->_fileHandlers[$filename]->close();
}
unset($this->_fileHandlers[$filename]);
}
/**
* Returns true if a file with the given $filename exists.
+3 -3
View File
@@ -15,21 +15,21 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_Search_Lucene_Storage_File
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Storage_File */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/File.php';
require_once 'Zend/Search/Lucene/Storage/File.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Storage_File_Filesystem extends Zend_Search_Lucene_Storage_File
@@ -41,7 +41,8 @@ class Zend_Search_Lucene_Storage_File_Filesystem extends Zend_Search_Lucene_Stor
*
* @var resource
*/
private $_fileHandle;
protected $_fileHandle;
/**
* Class constructor. Open the file.
@@ -53,6 +54,11 @@ class Zend_Search_Lucene_Storage_File_Filesystem extends Zend_Search_Lucene_Stor
{
global $php_errormsg;
if (strpos($mode, 'w') === false && !is_readable($filename)) {
// opening for reading non-readable file
throw new Zend_Search_Lucene_Exception('File \'' . $filename . '\' is not readable.');
}
$trackErrors = ini_get('track_errors');
ini_set('track_errors', '1');
@@ -185,12 +191,12 @@ class Zend_Search_Lucene_Storage_File_Filesystem extends Zend_Search_Lucene_Stor
* Lock type may be a LOCK_SH (shared lock) or a LOCK_EX (exclusive lock)
*
* @param integer $lockType
* @param boolean $nonBlockinLock
* @param boolean $nonBlockingLock
* @return boolean
*/
public function lock($lockType, $nonBlockinLock = false)
public function lock($lockType, $nonBlockingLock = false)
{
if ($nonBlockinLock) {
if ($nonBlockingLock) {
return flock($this->_fileHandle, $lockType | LOCK_NB);
} else {
return flock($this->_fileHandle, $lockType);
@@ -214,3 +220,4 @@ class Zend_Search_Lucene_Storage_File_Filesystem extends Zend_Search_Lucene_Stor
}
}
?>
@@ -15,23 +15,23 @@
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
/** Zend_Search_Lucene_Storage_File */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Storage/File.php';
require_once 'Zend/Search/Lucene/Storage/File.php';
/** Zend_Search_Lucene_Exception */
require_once $CFG->dirroot.'/search/Zend/Search/Lucene/Exception.php';
require_once 'Zend/Search/Lucene/Exception.php';
/**
* @category Zend
* @package Zend_Search_Lucene
* @subpackage Storage
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Search_Lucene_Storage_File_Memory extends Zend_Search_Lucene_Storage_File
+362
View File
@@ -0,0 +1,362 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for assignment activity module
*
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/assignment/lib.php");
/**
* a class for representing searchable information
*
*/
class AssignmentSearchDocument extends SearchDocument {
/**
* constructor
*/
public function __construct(&$assignmentitem, $assignment_module_id, $itemtype, $course_id, $owner_id, $context_id) {
// generic information; required
$doc->docid = $assignmentitem['id'];
$doc->documenttype = SEARCH_TYPE_ASSIGNMENT;
$doc->itemtype = $itemtype;
$doc->contextid = $context_id;
// we cannot call userdate with relevant locale at indexing time.
$doc->title = "{$itemtype}: {$assignmentitem['name']}";
$doc->date = $assignmentitem['date'];
//remove '(ip.ip.ip.ip)' from chat author list
$doc->author = $assignmentitem['authors'];
$doc->contents = $assignmentitem['description'];
$doc->url = assignment_make_link($assignment_module_id, $itemtype, $owner_id);
// module specific information; optional
$data->assignment = $assignment_module_id;
$data->assignmenttype = $assignmentitem['assignmenttype'];
// construct the parent class
parent::__construct($doc, $data, $course_id, 0, 0, 'mod/'.SEARCH_TYPE_ASSIGNMENT);
}
}
/**
* constructs a valid link to a chat content
* @param cm_id the chat course module
* @param start the start time of the session
* @param end th end time of the session
* @uses CFG
* @return a well formed link to session display
*/
function assignment_make_link($cm_id, $itemtype, $owner) {
global $CFG;
if ($itemtype == 'description')
return $CFG->wwwroot.'/mod/assignment/view.php?id='.$cm_id;
}
/**
* part of search engine API
*
*/
function assignment_iterator() {
if ($assignments = get_records('assignment'))
return $assignments;
else
return array();
}
/**
* part of search engine API
*
*/
function assignment_get_content_for_index(&$assignment) {
global $CFG;
$documents = array();
$course = get_record('course', 'id', $assignment->course);
$coursemodule = get_field('modules', 'id', 'name', 'assignment');
$cm = get_record('course_modules', 'course', $assignment->course, 'module', $coursemodule, 'instance', $assignment->id);
if ($cm){
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$assignment->authors = '';
$assignment->date = $assignment->timemodified;
$documents[] = new AssignmentSearchDocument(get_object_vars($assignment), $cm->id, 'description', $assignment->course, null, $context->id);
$submissions = assignment_get_all_submissions($assignment);
if ($submissions){
foreach($submissions as $submission){
$owner = get_record('user', 'id', $submission->userid);
$submission->authors = fullname($owner);
$submission->assignmenttype = $assignment->assignmenttype;
$submission->date = $submission->timemodified;
$submission->name = "submission:";
if (file_exists("{$CFG->dirroot}/mod/assignment/type/{$assignment->assignmenttype}/searchlib.php")){
include_once("{$CFG->dirroot}/mod/assignment/type/{$assignment->assignmenttype}/searchlib.php");
if (function_exists('assignment_get_submission_location')){
$submitted = assignment_get_submission_location($assignment, $submission);
}
}
if (empty($submitted)){
// this is for moodle legacy types that would need not to be patched for searchlib.php
switch($assignment->assignmenttype){
case 'online' : {
$submitted->source = 'text';
$submitted->data = $submission->data1;
}
break;
case 'uploadsingle' :
case 'upload' : {
$submitted->source = 'files';
$submitted->data = "{$assignment->course}/moddata/assignment/{$assignment->id}/{$submission->userid}";
}
break;
case 'offline' : continue; // cannot index, no content in Moodle !!
}
}
if (empty($submitted)) continue; // ignoring
if ($submitted->source = 'text'){
$submission->description = $submitted->data;
$submission->description = preg_replace("/<[^>]*>/", '', $submission->description); // stip all tags
$documents[] = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submission', $assignment->course, $submission->userid, $context->id);
mtrace("finished online submission for {$submission->authors} in assignement {$assignment->name}");
} elseif ($submitted->source = 'files'){
$SUBMITTED = opendir($submitted->path);
while($entry = readdir($SUBMITTED)){
if (ereg("^\.", $entry)) continue; // exclude hidden and dirs . and ..
$path = "{$submitted->path}/{$entry}";
$documents[] = assignment_get_physical_file($submission, $assignment, $cm, $path, $context_id, $documents);
mtrace("finished attachement $path for {$submission->authors} in assignement {$assignment->name}");
}
closedir($submission->path);
}
}
}
mtrace("finished assignment {$assignment->name}");
return $documents;
}
return array();
}
/**
* get text from a physical file in an assignment submission
* @param object $submission a submission for which to fetch some representative text
* @param object $assignment the relevant assignment as a context
* @param object $cm the corresponding coursemodule
* @param string $path a file from which to fetch some representative text
* @param int $contextid the moodle context if needed
* @param documents the array of documents, by ref, where to add the new document.
* @return a search document when unique or false.
*/
function assignment_get_physical_file(&$submission, &$assignment, &$cm, $path, $context_id, &$documents = null){
global $CFG;
$fileparts = pathinfo($path);
// cannot index unknown or masked types
if (empty($fileparts['extension'])) {
mtrace("Cannot index without explicit extension.");
return false;
}
$ext = strtolower($fileparts['extension']);
// cannot index unallowed or unhandled types
if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) {
mtrace($fileparts['extension'] . ' is not an allowed extension for indexing');
return false;
}
if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){
include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php');
$function_name = 'get_text_for_indexing_'.$ext;
$submission->description = $function_name(null, $path);
// get authors
$user = get_record('user', 'id', $submission->userid);
$submission->authors = fullname($user);
// we need a real id on file
$submission->id = "{$submission->id}/{$path}";
if (!empty($submission->description)){
if ($getsingle){
$single = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submitted', $assignment->course, $submission->userid, $context_id);
mtrace("finished submission file from {$submission->authors}");
return $single;
} else {
$documents[] = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submitted', $assignment->course, $submission->userid, $context_id);
}
mtrace("finished submission file from {$submission->authors}");
}
} else {
mtrace("fulltext handler not found for $ext type");
}
return false;
}
/**
* returns a single data search document based on an assignment
* @param string $id the id of the searchable item
* @param string $itemtype the type of information
*/
function assignment_single_document($id, $itemtype) {
if ($itemtype == 'requirement'){
if (!$assignment = get_record('assignment', 'id', $id)){
return null;
}
} elseif ($itemtype == 'submission') {
if ($submission = get_record('assignment_submissions', 'id', $id)){
$assignment = get_record('assignment', 'id', $submission->assignment);
} else {
return null;
}
}
$course = get_record('course', 'id', $assignment->course);
$coursemodule = get_field('modules', 'id', 'name', 'assignment');
$cm = get_record('course_modules', 'course', $course->id, 'module', $coursemodule, 'instance', $assignment->id);
if ($cm){
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
// should be only one
if ($itemtype == 'description'){
$document = new AssignmentSearchDocument(get_object_vars($assignment), $cm->id, 'description', $assignment->course, null, $context->id);
return $document;
}
if ($itemtype == 'submittted'){
$document = new AssignmentSearchDocument(get_object_vars($submission), $cm->id, 'submitted', $assignment->course, null, $context->id);
return $document;
}
}
return null;
}
/**
* dummy delete function that packs id with itemtype.
* this was here for a reason, but I can't remember it at the moment.
*
*/
function assignment_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
}
/**
* returns the var names needed to build a sql query for addition/deletions
* // TODO chat indexable records are virtual. Should proceed in a special way
*/
function assignment_db_names() {
//[primary id], [table name], [time created field name], [time modified field name]
return array(
array('id', 'assignment', 'timemodified', 'timemodified', 'description'),
array('id', 'assignment_submissions', 'timecreated', 'timemodified', 'submitted')
);
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
* function does not exist, the search engine assumes access is allowed.
* When this point is reached, we already know that :
* - user is legitimate in the surrounding context
* - user may be guest and guest access is allowed to the module
* - the function may perform local checks within the module information logic
* @param path the access path to the module script code
* @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
* @param this_id the item id within the information class denoted by entry_type. In chats, this id
* points out a session history which is a close sequence of messages.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG
* @return true if access is allowed, false elsewhere
*/
function assignment_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
global $CFG, $USER;
include_once("{$CFG->dirroot}/{$path}/lib.php");
// get the chat session and all related stuff
if ($itemtype == 'description'){
$assignment = get_record('assignment', 'id', $this_id);
} elseif ($itemtype == 'submitted'){
$submission = get_record('assignment_submissions', 'id', $this_id);
$assignment = get_record('assignment', 'id', $submission->assignment);
}
$context = get_record('context', 'id', $context_id);
$cm = get_record('course_modules', 'id', $context->instanceid);
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : hidden assignment ";
return false;
}
/*
group consistency check : checks the following situations about groups
// trap if user is not same group and groups are separated
$current_group = get_current_group($course->id);
$course = get_record('course', 'id', $assignment->course);
if ((groupmode($course, $cm) == SEPARATEGROUPS) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : assignment element is in separated group ";
return false;
}
*/
//user ownership check :
// trap if user is not owner of the resource and the ressource is a submission/attachement
if ($itemtype == 'submitted' && $USER->id != $submission->userid && !has_capability('mod/assignment:view', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : i'm not owner of this assignment ";
return false;
}
//date check : no submission may be viewed before timedue
if ($itemtype == 'submitted' && $assignment->timedue < time()){
if (!empty($CFG->search_access_debug)) echo "search reject : cannot read submissions before end of assignment ";
return false;
}
//ownership check : checks the following situations about user
// trap if user is not owner and cannot see other's entries
// TODO : typically may be stored into indexing cache
if (!has_capability('mod/assignment:view', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : cannot read past sessions ";
return false;
}
return true;
}
/**
* this call back is called when displaying the link for some last post processing
*
*/
function assignment_link_post_processing($title){
global $CFG;
if (!function_exists('search_assignment_getstring')){
function search_assignment_getstring($matches){
return get_string($matches[1], 'assignment');
}
}
$title = preg_replace_callback('/^(description|submitted)/', 'search_assignment_getstring', $title);
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+15 -12
View File
@@ -32,9 +32,9 @@ class ChatTrackSearchDocument extends SearchDocument {
/**
* constructor
*/
public function __construct(&$chatsession, $chat_module_id, $course_id, $group_id, $context_id) {
public function __construct(&$chatsession, $chat_id, $chat_module_id, $course_id, $group_id, $context_id) {
// generic information; required
$doc->docid = $chat_module_id.'-'.$chatsession['sessionstart'].'-'.$chatsession['sessionend'];
$doc->docid = $chat_id.'-'.$chatsession['sessionstart'].'-'.$chatsession['sessionend'];
$doc->documenttype = SEARCH_TYPE_CHAT;
$doc->itemtype = 'session';
$doc->contextid = $context_id;
@@ -50,10 +50,10 @@ class ChatTrackSearchDocument extends SearchDocument {
$doc->url = chat_make_link($chat_module_id, $chatsession['sessionstart'], $chatsession['sessionend']);
// module specific information; optional
$data->chat = $chat_module_id;
$data->chat = $chat_id;
// construct the parent class
parent::__construct($doc, $data, $course_id, $group_id, 0, PATH_FOR_SEARCH_TYPE_CHAT);
parent::__construct($doc, $data, $course_id, $group_id, 0, 'mod/'.SEARCH_TYPE_CHAT);
}
}
@@ -176,7 +176,7 @@ function chat_get_content_for_index(&$chat) {
foreach($aTrack->sessionusers as $aUserId){
$user = get_record('user', 'id', $aUserId);
$aTrack->authors = ($user) ? fullname($user) : '' ;
$documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $cm->id, $chat->course, $aTrack->groupid, $context->id);
$documents[] = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat->id, $cm->id, $chat->course, $aTrack->groupid, $context->id);
}
}
}
@@ -207,7 +207,7 @@ function chat_single_document($id, $itemtype) {
$tracks = chat_get_session_tracks($chat->id, $sessionstart, $sessionstart);
if ($tracks){
$aTrack = $tracks[0];
$document = new ChatTrackSearchDocument(get_object_vars($aTrack), $cm->id, $chat->course, $aTrack->groupid, $context->id);
$document = new ChatTrackSearchDocument(get_object_vars($aTrack), $chat_id, $cm->id, $chat->course, $aTrack->groupid, $context->id);
return $document;
}
}
@@ -255,8 +255,7 @@ function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
include_once("{$CFG->dirroot}/{$path}/lib.php");
list($chat_id, $sessionstart, $sessionend) = split('-', $id);
list($chat_id, $sessionstart, $sessionend) = split('-', $this_id);
// get the chat session and all related stuff
$chat = get_record('chat', 'id', $chat_id);
$context = get_record('context', 'id', $context_id);
@@ -271,7 +270,6 @@ function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
//group consistency check : checks the following situations about groups
// trap if user is not same group and groups are separated
$current_group = get_current_group($course->id);
$course = get_record('course', 'id', $chat->course);
if ((groupmode($course, $cm) == SEPARATEGROUPS) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : chat element is in separated group ";
@@ -294,8 +292,13 @@ function chat_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
*
*/
function chat_link_post_processing($title){
setLocale(LC_TIME, substr(current_language(), 0, 2));
$title = preg_replace('/TT_(.*)_TT/e', "userdate(\\1)", $title);
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
setLocale(LC_TIME, substr(current_language(), 0, 2));
$title = preg_replace('/TT_(.*)_TT/e', "userdate(\\1)", $title);
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+12 -7
View File
@@ -54,7 +54,7 @@ class DataSearchDocument extends SearchDocument {
$data->database = $record['dataid'];
// construct the parent class
parent::__construct($doc, $data, $course_id, $record['groupid'], $record['userid'], PATH_FOR_SEARCH_TYPE_DATA);
parent::__construct($doc, $data, $course_id, $record['groupid'], $record['userid'], 'mod/'.SEARCH_TYPE_DATA);
}
}
@@ -203,6 +203,7 @@ function data_get_content_for_index(&$database) {
unset($records_content[$aRecordId]['_first']);
// concatenates all other texts
$content = '';
foreach($records_content[$aRecordId] as $aField){
$content = @$content.' '.$aField;
}
@@ -348,7 +349,6 @@ function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
//group consistency check : checks the following situations about groups
// trap if user is not same group and groups are separated
$current_group = get_current_group($course->id);
$course = get_record('course', 'id', $data->course);
if ((groupmode($course, $cm) == SEPARATEGROUPS) && !ismember($group_id) && !has_capability('moodle/site:accessallgroups', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : separated group owned resource ";
@@ -368,7 +368,7 @@ function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
// trap if unapproved and has not approval capabilities
// TODO : report a potential capability lack of : mod/data:approve
$approval = get_field('data_records', 'approved', 'id', $record->id);
if (!$approval && !isteacher($data->course) && !has_capability('mod/data:manageentries', $context)){
if (!$approval && !has_capability('mod/data:manageentries', $context)){
if (!empty($CFG->search_access_debug)) echo "search reject : unapproved resource ";
return false;
}
@@ -377,7 +377,7 @@ function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
// trap if too few records
// TODO : report a potential capability lack of : mod/data:viewhiddenentries
$recordsAmount = count_records('data_records', 'dataid', $data->id);
if ($data->requiredentriestoview > $recordsAmount && !isteacher($data->course) && !has_capability('mod/data:manageentries', $context)) {
if ($data->requiredentriestoview > $recordsAmount && !has_capability('mod/data:manageentries', $context)) {
if (!empty($CFG->search_access_debug)) echo "search reject : not enough records to view ";
return false;
}
@@ -387,12 +387,12 @@ function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
// TODO : report a potential capability lack of : mod/data:viewhiddenentries
$now = usertime(time());
if ($data->timeviewfrom > 0)
if ($now < $data->timeviewfrom && !isteacher($data->course) && !has_capability('mod/data:manageentries', $context)) {
if ($now < $data->timeviewfrom && !has_capability('mod/data:manageentries', $context)) {
if (!empty($CFG->search_access_debug)) echo "search reject : still not open activity ";
return false;
}
if ($data->timeviewto > 0)
if ($now > $data->timeviewto && !isteacher($data->course) && !has_capability('mod/data:manageentries', $context)) {
if ($now > $data->timeviewto && !has_capability('mod/data:manageentries', $context)) {
if (!empty($CFG->search_access_debug)) echo "search reject : closed activity ";
return false;
}
@@ -405,7 +405,12 @@ function data_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
* @param string $title
*/
function data_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+11 -1
View File
@@ -17,7 +17,7 @@
*
*/
abstract class SearchDocument extends Zend_Search_Lucene_Document {
public function __construct(&$doc, &$data, $course_id, $group_id, $user_id, $path) {
public function __construct(&$doc, &$data, $course_id, $group_id, $user_id, $path, $additional_keyset = null) {
//document identification and indexing
$this->addField(Zend_Search_Lucene_Field::Keyword('docid', $doc->docid));
//document type : the name of the Moodle element that manages it
@@ -59,6 +59,16 @@ abstract class SearchDocument extends Zend_Search_Lucene_Document {
// of multiple capabilities in their code. This possibility should be left open here.
$this->addField(Zend_Search_Lucene_Field::UnIndexed('capabilities', $caps));
*/
/*
// Additional key set allows a module to ask for extensible criteria based search
// depending on the module internal needs.
*/
if (!empty($additional_keyset)){
foreach($additional_keyset as $keyname => $keyvalue){
$this->addField(Zend_Search_Lucene_Field::Keyword($keyname, $keyvalue));
}
}
}
}
+14 -4
View File
@@ -51,7 +51,7 @@ class ForumSearchDocument extends SearchDocument {
$data->forum = $forum_id;
$data->discussion = $post['discussion'];
parent::__construct($doc, $data, $course_id, $post['groupid'], $post['userid'], PATH_FOR_SEARCH_TYPE_FORUM);
parent::__construct($doc, $data, $course_id, $post['groupid'], $post['userid'], 'mod/'.SEARCH_TYPE_FORUM);
}
}
@@ -87,6 +87,7 @@ function forum_get_content_for_index(&$forum) {
if (!$forum) return $documents;
$posts = forum_get_discussions_fast($forum->id);
mtrace("Found ".count($posts)." discussions to analyse in forum ".$forum->name);
if (!$posts) return $documents;
$coursemodule = get_field('modules', 'id', 'name', 'forum');
@@ -96,11 +97,13 @@ function forum_get_content_for_index(&$forum) {
foreach($posts as $aPost) {
$aPost->itemtype = 'head';
if ($aPost) {
if (strlen($aPost->message) > 0) {
if (!empty($aPost->message)) {
echo "*";
$documents[] = new ForumSearchDocument(get_object_vars($aPost), $forum->id, $forum->course, 'head', $context->id);
}
if ($children = forum_get_child_posts_fast($aPost->id, $forum->id)) {
foreach($children as $aChild) {
echo ".";
$aChild->itemtype = 'post';
if (strlen($aChild->message) > 0) {
$documents[] = new ForumSearchDocument(get_object_vars($aChild), $forum->id, $forum->course, 'post', $context->id);
@@ -109,6 +112,7 @@ function forum_get_content_for_index(&$forum) {
}
}
}
mtrace("Finished discussion");
return $documents;
}
@@ -166,7 +170,8 @@ function forum_get_discussions_fast($forum_id) {
$timelimit='';
if (!empty($CFG->forum_enabletimedposts)) {
if (!((isadmin() and !empty($CFG->admineditalways)) || isteacher(get_field('forum', 'course', 'id', $forum_id)))) {
if (!((has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))
and !empty($CFG->admineditalways)) || isteacher(get_field('forum', 'course', 'id', $forum_id)))) {
$now = time();
$timelimit = " AND ((d.timestart = 0 OR d.timestart <= '$now') AND (d.timeend = 0 OR d.timeend > '$now')";
if (!empty($USER->id)) {
@@ -302,7 +307,12 @@ function forum_check_text_access($path, $itemtype, $this_id, $user, $group_id, $
* @param string $title
*/
function forum_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+10 -5
View File
@@ -52,7 +52,7 @@ class GlossarySearchDocument extends SearchDocument {
$data->glossary = $entry['glossaryid'];
// construct the parent class
parent::__construct($doc, $data, $course_id, -1, $entry['userid'], PATH_FOR_SEARCH_TYPE_GLOSSARY);
parent::__construct($doc, $data, $course_id, -1, $entry['userid'], 'mod/'.SEARCH_TYPE_GLOSSARY);
}
}
@@ -122,6 +122,7 @@ function glossary_iterator() {
* @return an array of searchable documents
*/
function glossary_get_content_for_index(&$glossary) {
// global $DB;
// get context
$coursemodule = get_field('modules', 'id', 'name', 'glossary');
@@ -144,8 +145,7 @@ function glossary_get_content_for_index(&$glossary) {
// index comments
if (count($entryIds)){
$entryIdList = implode(',', $entryIds);
$comments = get_records_list('glossary_comments', 'entryid', $entryIdList);
$comments = get_records_list('glossary_comments', 'entryid', implode(',',$entryIds));
if ($comments){
foreach($comments as $comment) {
if (strlen($comment->entrycomment) > 0) {
@@ -227,7 +227,7 @@ function glossary_check_text_access($path, $itemtype, $this_id, $user, $group_id
global $CFG;
// get the glossary object and all related stuff
$entry = get_record('glossary_entries', 'id', $id);
$entry = get_record('glossary_entries', 'id', $this_id);
$glossary = get_record('glossary', 'id', $entry->glossaryid);
$context = get_record('context', 'id', $context_id);
$cm = get_record('course_modules', 'id', $context->instanceid);
@@ -251,7 +251,12 @@ function glossary_check_text_access($path, $itemtype, $this_id, $user, $group_id
* @param string $title
*/
function glossary_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+184
View File
@@ -0,0 +1,184 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.9
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for all resources
* This file contains the mapping between a resource and it's indexable counterpart,
*
* Functions for iterating and retrieving the necessary records are now also included
* in this file, rather than mod/resource/lib.php
*/
/**
* requires and includes
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/resource/lib.php");
/* *
* a class for representing searchable information
*
*/
class LabelSearchDocument extends SearchDocument {
public function __construct(&$label, $context_id) {
// generic information; required
$doc->docid = $label['course'];
$doc->documenttype = SEARCH_TYPE_LABEL;
$doc->itemtype = 'label';
$doc->contextid = $context_id;
$doc->title = strip_tags($label['name']);
$doc->date = $label['timemodified'];
$doc->author = '';
$doc->contents = strip_tags($label['name']);
$doc->url = label_make_link($label['course']);
// module specific information; optional
$data = array();
// construct the parent class
parent::__construct($doc, $data, $label['course'], 0, 0, 'mod/'.SEARCH_TYPE_LABEL);
} //constructor
}
/**
* constructs valid access links to information
* @param resourceId the of the resource
* @return a full featured link element as a string
*/
function label_make_link($course_id) {
global $CFG;
return $CFG->wwwroot.'/course/view.php?id='.$course_id;
}
/**
* part of standard API
*
*/
function label_iterator() {
//trick to leave search indexer functionality intact, but allow
//this document to only use the below function to return info
//to be searched
$labels = get_records('label');
return $labels;
}
/**
* part of standard API
* this function does not need a content iterator, returns all the info
* itself;
* @param notneeded to comply API, remember to fake the iterator array though
* @uses CFG
* @return an array of searchable documents
*/
function label_get_content_for_index(&$label) {
global $CFG;
// starting with Moodle native resources
$documents = array();
$coursemodule = get_field('modules', 'id', 'name', 'label');
$cm = get_record('course_modules', 'course', $label->course, 'module', $coursemodule, 'instance', $label->id);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$documents[] = new LabelSearchDocument(get_object_vars($label), $context->id);
mtrace("finished label {$label->id}");
return $documents;
}
/**
* part of standard API.
* returns a single resource search document based on a label id
* @param id the id of the accessible document
* @return a searchable object or null if failure
*/
function label_single_document($id, $itemtype) {
global $CFG;
$label = get_record('label', 'id', $id);
if ($label){
$coursemodule = get_field('modules', 'id', 'name', 'label');
$cm = get_record('course_modules', 'id', $label->id);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
return new LabelSearchDocument(get_object_vars($label), $context->id);
}
return null;
}
/**
* dummy delete function that aggregates id with itemtype.
* this was here for a reason, but I can't remember it at the moment.
*
*/
function label_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //resource_delete
/**
* returns the var names needed to build a sql query for addition/deletions
*
*/
function label_db_names() {
//[primary id], [table name], [time created field name], [time modified field name], [docsubtype], [additional where conditions for sql]
return array(array('id', 'label', 'timemodified', 'timemodified', 'label', ''));
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
* function does not exist, the search engine assumes access is allowed.
* @param path the access path to the module script code
* @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
* @param this_id the item id within the information class denoted by itemtype. In resources, this id
* points to the resource record and not to the module that shows it.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @return true if access is allowed, false elsewhere
*/
function label_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
global $CFG;
// include_once("{$CFG->dirroot}/{$path}/lib.php");
$r = get_record('label', 'id', $this_id);
$module_context = get_record('context', 'id', $context_id);
$cm = get_record('course_modules', 'id', $module_context->instanceid);
$course_context = get_context_instance(COURSE_CONTEXT, $r->course);
//check if englobing course is visible
if (!has_capability('moodle/course:view', $course_context)){
return false;
}
//check if found course module is visible
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $module_context)){
return false;
}
return true;
}
/**
* post processes the url for cleaner output.
* @param string $title
*/
function label_link_post_processing($title){
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding("(".shorten_text(clean_text($title), 60)."...) ", 'UTF-8', 'auto');
}
return mb_convert_encoding("(".shorten_text(clean_text($title), 60)."...) ", 'auto', 'UTF-8');
}
?>
+12 -4
View File
@@ -49,7 +49,7 @@ class LessonPageSearchDocument extends SearchDocument {
// module specific information
$data->lesson = $page['lessonid'];
parent::__construct($doc, $data, $course_id, 0, 0, PATH_FOR_SEARCH_TYPE_LESSON);
parent::__construct($doc, $data, $course_id, 0, 0, 'mod/'.SEARCH_TYPE_LESSON);
}
}
@@ -73,8 +73,11 @@ function lesson_make_link($lessonmoduleid, $itemid, $itemtype) {
*
*/
function lesson_iterator() {
$lessons = get_records('lesson');
return $lessons;
if ($lessons = get_records('lesson')){
return $lessons;
} else {
return array();
}
}
/**
@@ -210,7 +213,12 @@ function lesson_check_text_access($path, $itemtype, $this_id, $user, $group_id,
*
*/
function lesson_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+14 -13
View File
@@ -16,13 +16,13 @@
/**
* MS Word extractor
* @param object $resource
* @uses CFG, USER
* @uses $CFG
*/
function get_text_for_indexing_doc(&$resource){
global $CFG, $USER;
function get_text_for_indexing_doc(&$resource, $directfile = ''){
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
$moodleroot = (@$CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ;
@@ -30,26 +30,27 @@ function get_text_for_indexing_doc(&$resource){
if (!empty($CFG->block_search_word_to_text_cmd)){
if (!file_exists("{$moodleroot}{$CFG->block_search_word_to_text_cmd}")){
mtrace('Error with MSWord to text converter command : exectuable not found.');
}
else{
$file = escapeshellarg($CFG->dataroot.'/'.$resource->course.'/'.$resource->reference);
} else {
if ($directfile == ''){
$file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}");
} else {
$file = escapeshellarg("{$CFG->dataroot}/{$directfile}");
}
$command = trim($CFG->block_search_word_to_text_cmd);
$text_converter_cmd = "{$moodleroot}{$command} $file";
$text_converter_cmd = "{$moodleroot}{$command} -m UTF-8.txt $file";
if ($CFG->block_search_word_to_text_env){
putenv($CFG->block_search_word_to_text_env);
}
mtrace("Executing : $text_converter_cmd");
$result = shell_exec($text_converter_cmd);
if ($result){
return mb_convert_encoding($result, 'UTF8', 'auto');
}
else{
return mb_convert_encoding($result, 'UTF-8', 'auto');
} else {
mtrace('Error with MSWord to text converter command : execution failed. ');
return '';
}
}
}
else {
} else {
mtrace('Error with MSWord to text converter command : command not set up. Execute once search block configuration.');
return '';
}
+10 -6
View File
@@ -15,16 +15,20 @@
/**
* @param object $resource
* @uses CFG, USER
* @uses $CFG
*/
function get_text_for_indexing_htm(&$resource){
global $CFG, $USER;
function get_text_for_indexing_htm(&$resource, $directfile = ''){
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
// just get text
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
if ($directfile == ''){
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
} else {
$text = implode('', file("{$CFG->dataroot}/{$directfile}"));
}
// extract keywords and other interesting meta information and put it back as real content for indexing
if (preg_match('/(.*)<meta ([^>]*)>(.*)/is', $text, $matches)){
@@ -40,7 +44,7 @@ function get_text_for_indexing_htm(&$resource){
$text = preg_replace("/<[^>]*>/", '', $text);
$text = preg_replace("/<!--[^>]*-->/", '', $text);
$text = html_entity_decode($text, ENT_COMPAT, 'UTF-8');
$text = mb_convert_encoding($text, 'UTF-8', 'AUTO');
$text = mb_convert_encoding($text, 'UTF-8', 'auto');
/*
* debug code for tracing input
+2 -2
View File
@@ -16,10 +16,10 @@
/**
* @param object $resource
*/
function get_text_for_indexing_html(&$resource){
function get_text_for_indexing_html(&$resource, $directfile = ''){
// wraps to htm handler
include_once 'physical_htm.php';
return get_text_for_indexing_htm($resource);
return get_text_for_indexing_htm($resource, $directfile);
}
?>
+55
View File
@@ -0,0 +1,55 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* this is a format handler for getting text out of the opensource ODT binary format
* so it can be indexed by Lucene search engine
*/
/**
* OpenOffice Odt extractor
* @param object $resource
* @uses $CFG
*/
function get_text_for_indexing_odt(&$resource, $directfile = ''){
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
$moodleroot = (@$CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ;
// just call pdftotext over stdout and capture the output
if (!empty($CFG->block_search_odt_to_text_cmd)){
if (!file_exists("{$moodleroot}{$CFG->block_search_odt_to_text_cmd}")){
mtrace('Error with OpenOffice ODT to text converter command : exectuable not found.');
} else {
if ($directfile == ''){
$file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}");
} else {
$file = escapeshellarg("{$CFG->dataroot}/{$directfile}");
}
$command = trim($CFG->block_search_odt_to_text_cmd);
$text_converter_cmd = "{$moodleroot}{$command} --encoding=UTF-8 $file";
mtrace("Executing : $text_converter_cmd");
$result = shell_exec($text_converter_cmd);
if ($result){
return $result;
} else {
mtrace('Error with OpenOffice ODT to text converter command : execution failed. ');
return '';
}
}
} else {
mtrace('Error with OpenOffice ODT to text converter command : command not set up. Execute once search block configuration.');
return '';
}
}
?>
+12 -11
View File
@@ -15,13 +15,13 @@
/**
* @param object $resource
* @uses CFG, USER
* @uses $CFG
*/
function get_text_for_indexing_pdf(&$resource){
global $CFG, $USER;
function get_text_for_indexing_pdf(&$resource, $directfile = ''){
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
// adds moodle root switch if none was defined
if (!isset($CFG->block_search_usemoodleroot)){
@@ -35,22 +35,23 @@ function get_text_for_indexing_pdf(&$resource){
preg_match("/^\S+/", $CFG->block_search_pdf_to_text_cmd, $matches);
if (!file_exists("{$moodleroot}{$matches[0]}")){
mtrace('Error with pdf to text converter command : executable not found at '.$moodleroot.$matches[0]);
}
else{
$file = escapeshellarg($CFG->dataroot.'/'.$resource->course.'/'.$resource->reference);
} else {
if ($directfile == ''){
$file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}");
} else {
$file = escapeshellarg("{$CFG->dataroot}/{$directfile}");
}
$command = trim($CFG->block_search_pdf_to_text_cmd);
$text_converter_cmd = "{$moodleroot}{$command} $file -";
$result = shell_exec($text_converter_cmd);
if ($result){
return $result;
}
else{
} else {
mtrace('Error with pdf to text converter command : execution failed for '.$text_converter_cmd.'. Check for execution permission on pdf converter executable.');
return '';
}
}
}
else {
} else {
mtrace('Error with pdf to text converter command : command not set up. Execute once search block configuration.');
return '';
}
+9 -5
View File
@@ -29,17 +29,21 @@
/**
* @param object $resource
* @uses CFG, USER
* @uses $CFG
*/
function get_text_for_indexing_ppt(&$resource){
global $CFG, $USER;
function get_text_for_indexing_ppt(&$resource, $directfile = ''){
global $CFG;
$indextext = null;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
if ($directfile == ''){
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
} else {
$text = implode('', file("{$CFG->dataroot}/{$directfile}"));
}
$remains = $text;
$fragments = array();
+69
View File
@@ -0,0 +1,69 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* @note : The Adobe SWF Converters library is not GPL, although it can be of free use in some
* situations. This file is provided for convenience, but should use having a glance at
* {@link http://www.adobe.com/licensing/developer/}
*
* this is a format handler for getting text out of a proprietary binary format
* so it can be indexed by Lucene search engine
*/
/**
* @param object $resource
* @uses $CFG
*/
function get_text_for_indexing_swf(&$resource, $directfile = ''){
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
// adds moodle root switch if none was defined
if (!isset($CFG->block_search_usemoodleroot)){
set_config('block_search_usemoodleroot', 1);
}
$moodleroot = ($CFG->block_search_usemoodleroot) ? "{$CFG->dirroot}/" : '' ;
// just call pdftotext over stdout and capture the output
if (!empty($CFG->block_search_pdf_to_text_cmd)){
$command = trim($CFG->block_search_swf_to_text_cmd);
if (!file_exists("{$moodleroot}{$command}")){
mtrace('Error with swf to text converter command : executable not found as '.$moodleroot.$command);
} else {
if ($directfile == ''){
$file = escapeshellarg("{$CFG->dataroot}/{$resource->course}/{$resource->reference}");
} else {
$file = escapeshellarg("{$CFG->dataroot}/{$directfile}");
}
$text_converter_cmd = "{$moodleroot}{$command} -t $file";
$result = shell_exec($text_converter_cmd);
// result is in html. We must strip it off
$result = preg_replace("/<[^>]*>/", '', $result);
$result = preg_replace("/<!--[^>]*-->/", '', $result);
$result = html_entity_decode($result, ENT_COMPAT, 'UTF-8');
$result = mb_convert_encoding($result, 'UTF-8', 'auto');
if ($result){
return $result;
} else {
mtrace('Error with swf to text converter command : execution failed for '.$text_converter_cmd.'. Check for execution permission on swf converter executable.');
return '';
}
}
} else {
mtrace('Error with swf to text converter command : command not set up. Execute once search block configuration.');
return '';
}
}
?>
+10 -5
View File
@@ -15,16 +15,21 @@
/**
* @param object $resource
* @uses CFG, USER
* @uses $CFG
*/
function get_text_for_indexing_txt(&$resource){
global $CFG, $USER;
function get_text_for_indexing_txt(&$resource, $directfile = ''){
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
// just try to get text empirically from ppt binary flow
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
if ($directfile == ''){
$text = implode('', file("{$CFG->dataroot}/{$resource->course}/{$resource->reference}"));
} else {
$text = implode('', file("{$CFG->dataroot}/{$directfile}"));
}
if (!empty($CFG->block_search_limit_index_body)){
$text = shorten($text, $CFG->block_search_limit_index_body);
}
+3 -3
View File
@@ -15,13 +15,13 @@
/**
* @param object $resource
* @uses CFG, USER
* @uses $CFG
*/
function get_text_for_indexing_xml(&$resource, $directfile = ''){
global $CFG, $USER;
global $CFG;
// SECURITY : do not allow non admin execute anything on system !!
if (!isadmin($USER->id)) return;
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) return;
// just get text
if ($directfile == ''){
+17 -14
View File
@@ -44,7 +44,7 @@ class ResourceSearchDocument extends SearchDocument {
$data = array();
// construct the parent class
parent::__construct($doc, $data, $resource['course'], 0, 0, PATH_FOR_SEARCH_TYPE_RESOURCE);
parent::__construct($doc, $data, $resource['course'], 0, 0, 'mod/'.SEARCH_TYPE_RESOURCE);
} //constructor
} //ResourceSearchDocument
@@ -95,15 +95,15 @@ function resource_get_content_for_index(&$notneeded) {
alltext != '&nbsp;' AND
type != 'file'
";
$resources = get_records_sql($query);
foreach($resources as $aResource){
$coursemodule = get_field('modules', 'id', 'name', 'resource');
$cm = get_record('course_modules', 'course', $aResource->course, 'module', $coursemodule, 'instance', $aResource->id);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$aResource->id = $cm->id;
$documents[] = new ResourceSearchDocument(get_object_vars($aResource), $context->id);
mtrace("finished $aResource->name");
if ($resources = get_records_sql($query)){
foreach($resources as $aResource){
$coursemodule = get_field('modules', 'id', 'name', 'resource');
$cm = get_record('course_modules', 'course', $aResource->course, 'module', $coursemodule, 'instance', $aResource->id);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$aResource->id = $cm->id;
$documents[] = new ResourceSearchDocument(get_object_vars($aResource), $context->id);
mtrace("finished $aResource->name");
}
}
// special physical files handling
@@ -135,10 +135,8 @@ function resource_get_content_for_index(&$notneeded) {
cm.module = m.id AND
m.name = 'resource'
";
$resources = get_records_sql($query);
if ($resources = get_records_sql($query)){
// invokes external content extractor if exists.
if ($resources){
foreach($resources as $aResource){
// fetches a physical indexable document and adds it to documents passed by ref
$coursemodule = get_field('modules', 'id', 'name', 'resource');
@@ -323,6 +321,11 @@ function resource_check_text_access($path, $itemtype, $this_id, $user, $group_id
* @param string $title
*/
function resource_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
-301
View File
@@ -1,301 +0,0 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Michael Campanis, Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* document handling for techproject activity module
*/
/**
* requires and includes
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/mod/techproject/lib.php");
/**
* a class for representing searchable information
*
*/
class TechprojectEntrySearchDocument extends SearchDocument {
/**
* constructor
*
*/
public function __construct(&$entry, $course_id, $context_id) {
// generic information
$doc->docid = $entry['id'];
$doc->documenttype = SEARCH_TYPE_TECHPROJECT;
$doc->itemtype = $entry['entry_type'];
$doc->contextid = $context_id;
$doc->title = $entry['abstract'];
$doc->author = ($entry['userid']) ? $entry['author'] : '';
$doc->contents = strip_tags($entry['description']);
$doc->date = '';
$doc->url = techproject_make_link($entry['projectid'], $entry['id'], $entry['entry_type'], $entry['groupid']);
// module specific information
$data->techproject = $entry['projectid'];
parent::__construct($doc, $data, $course_id, $entry['groupid'], $entry['userid'], PATH_FOR_SEARCH_TYPE_TECHPROJECT);
} //constructor
} //TechprojectEntrySearchDocument
/**
* constructs a valid link to a description detail
*
*/
function techproject_make_link($techproject_id, $entry_id, $entry_type, $group_id) {
global $CFG;
return $CFG->wwwroot.'/mod/techproject/view.php?view=view_detail&amp;id='.$techproject_id.'&amp;objectId='.$entry_id.'&amp;objectClass='.$entry_type.'&amp;group='.$group_id;
} //techproject_make_link
/**
* search standard API
*
*/
function techproject_iterator() {
$techprojects = get_records('techproject');
return $techprojects;
} //techproject_iterator
/**
* search standard API
* @param techproject a techproject instance
* @return an array of collected searchable documents
*/
function techproject_get_content_for_index(&$techproject) {
$documents = array();
if (!$techproject) return $documents;
$requirements = techproject_get_entries($techproject->id, 'requirement');
$specifications = techproject_get_entries($techproject->id, 'specification');
$tasks = techproject_get_tasks($techproject->id);
$milestones = techproject_get_entries($techproject->id, 'milestone');
$deliverables = techproject_get_entries($techproject->id, 'deliverable');
$coursemodule = get_field('modules', 'id', 'name', 'techproject');
$cm = get_record('course_modules', 'course', $techproject->course, 'module', $coursemodule, 'instance', $techproject->id);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$entries = @array_merge($requirements, $specifications, $milestones, $deliverables);
if ($entries){
foreach($entries as $anEntry) {
if ($anEntry) {
if (strlen($anEntry->description) > 0) {
$anEntry->author = '';
$documents[] = new TechprojectEntrySearchDocument(get_object_vars($anEntry), $techproject->course, $context->id);
}
}
}
}
if ($tasks){
foreach($tasks as $aTask) {
if ($aTask) {
if (strlen($aTask->description) > 0) {
if ($aTask->assignee){
$user = get_record('user', 'id', $aTask->assignee);
$aTask->author = $user->firstname.' '.$user->lastname;
}
$documents[] = new TechprojectEntrySearchDocument(get_object_vars($aTask), $techproject->course, $context->id);
}
}
}
}
return $documents;
} //techproject_get_content_for_index
/**
* returns a single techproject search document based on a techproject_entry id and itemtype
*
*/
function techproject_single_document($id, $itemtype) {
switch ($itemtype){
case 'requirement':{
$entry = get_record('techproject_requirement', 'id', $id);
$entry->author = '';
break;
}
case 'specification':{
$entry = get_record('techproject_specification', 'id', $id);
$entry->author = '';
break;
}
case 'milestone':{
$entry = get_record('techproject_milestone', 'id', $id);
$entry->author = '';
break;
}
case 'deliverable':{
$entry = get_record('techproject_deliverable', 'id', $id);
$entry->author = '';
break;
}
case 'task':{
$entry = get_record('techproject_task', 'id', $id);
if ($entry->assignee){
$user = get_record('user', 'id', $entry->assignee);
$entry->author = $user->firstname.' '.$user->lastname;
}
break;
}
}
$techproject_course = get_field('techproject', 'course', 'id', $entry->projectid);
$coursemodule = get_field('modules', 'id', 'name', 'techproject');
$cm = get_record('course_modules', 'course', $techproject_course, 'module', $coursemodule, 'instance', $entry->projectid);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
$entry->type = $itemtype;
$techproject = get_record('techproject', 'id', $requirement->projectid);
return new TechprojectEntrySearchDocument(get_object_vars($anEntry), $techproject->course, $context->id);
} //techproject_single_document
/**
* dummy delete function that packs id with itemtype.
* this was here for a reason, but I can't remember it at the moment.
*
*/
function techproject_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
} //techproject_delete
/**
* returns the var names needed to build a sql query for addition/deletions
*
*/
// TODO : what should we do there ?
function techproject_db_names() {
//[primary id], [table name], [time created field name], [time modified field name]
return array(
array('id', 'techproject_requirement', 'created', 'modified', 'requirement'),
array('id', 'techproject_specification', 'created', 'modified', 'specification'),
array('id', 'techproject_task', 'created', 'modified', 'task'),
array('id', 'techproject_milestone', 'created', 'modified', 'milestone'),
array('id', 'techproject_deliverable', 'created', 'modified', 'deliverable')
);
} //techproject_db_names
/**
* get a complete list of entries of one particular type
* @param techprojectId the project instance
* @param type the entity type
* @return an array of records
*/
function techproject_get_entries($techproject_id, $type) {
global $CFG;
$query = "
SELECT
e.id,
e.abstract,
e.description,
e.projectid,
e.groupid,
e.userid,
'$type' AS entry_type
FROM
{$CFG->prefix}techproject_{$type} AS e
WHERE
e.projectid = '{$techproject_id}'
";
return get_records_sql($query);
} //techproject_get_entries
/**
* get the task list for a project instance
* @param techprojectId the project
* @return an array of records that represent tasks
*/
function techproject_get_tasks($techproject_id) {
global $CFG;
$query = "
SELECT
t.id,
t.abstract,
t.description,
t.projectid,
t.groupid,
t.owner as userid,
u.firstname,
u.lastname,
'task' as entry_type
FROM
{$CFG->prefix}techproject_task AS t
LEFT JOIN
{$CFG->prefix}user AS u
ON
t.owner = u.id
WHERE
t.projectid = '{$techproject_id}'
ORDER BY
t.taskstart ASC
";
return get_records_sql($query);
} //techproject_get_tasks
/**
* this function handles the access policy to contents indexed as searchable documents. If this
* function does not exist, the search engine assumes access is allowed.
* When this point is reached, we already know that :
* - user is legitimate in the surrounding context
* - user may be guest and guest access is allowed to the module
* - the function may perform local checks within the module information logic
* @param path the access path to the module script code
* @param entry_type the information subclassing (usefull for complex modules, defaults to 'standard')
* @param this_id the item id within the information class denoted by entry_type. In techprojects, this id
* points to the techproject instance in which all resources are indexed.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @return true if access is allowed, false elsewhere
*/
function techproject_check_text_access($path, $entry_type, $this_id, $user, $group_id, $context_id){
global $CFG;
include_once("{$CFG->dirroot}/{$path}/lib.php");
// get the techproject object and all related stuff
$techproject = get_record('techproject', 'id', $this_id);
$course = get_record('course', 'id', $techproject->course);
$module_context = get_record('context', 'id', $context_id);
$cm = get_record('course_modules', 'id', $module_context->instanceid);
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $module_context)) return false;
//group consistency check : checks the following situations about groups
// if user is guest check access capabilities for guests :
// guests can see default project, and other records if groups are liberal
// TODO : change guestsallowed in a capability
if (isguest() && $techproject->guestsallowed){
if ($group_id && groupmode($course, $cm) == SEPARATEGROUPS)
return false;
return true;
}
// trap if user is not same group and groups are separated
$current_group = get_current_group($course->id);
if ((groupmode($course) == SEPARATEGROUPS) && $group_id != $current_group && $group_id) return false;
//trap if ungroupedsees is off in strict access mode and user is not teacher
if ((groupmode($course) == SEPARATEGROUPS) && !$techproject->ungroupedsees && !$group_id && isteacher($user->id)) return false;
return true;
} //techproject_check_text_access
/**
* this call back is called when displaying the link for some last post processing
*
*/
function techproject_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
?>
+366
View File
@@ -0,0 +1,366 @@
<?php
/**
* Global Search Engine for Moodle
*
* @package search
* @category core
* @subpackage document_wrappers
* @author Valery Fremaux [[email protected]] > 1.8
* @date 2008/03/31
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*
* special (EXTRA) document handling for user related data
*
*/
/**
* includes and requires
*/
require_once("$CFG->dirroot/search/documents/document.php");
require_once("$CFG->dirroot/blog/lib.php");
/**
* a class for representing searchable information in user metadata
*
*/
class UserSearchDocument extends SearchDocument {
/**
* constructor
*/
public function __construct(&$userhash, $user_id, $context_id) {
// generic information; required
$doc->docid = $userhash['id'];
$doc->documenttype = SEARCH_TYPE_USER;
$doc->itemtype = 'user';
$doc->contextid = $context_id;
$user = get_record('user', 'id', $user_id);
$doc->title = get_string('user').': '.fullname($user);
$doc->date = ($userhash['lastaccess']) ? $userhash['lastaccess'] : time() ;
//remove '(ip.ip.ip.ip)' from chat author list
$doc->author = $user->id;
$doc->contents = $userhash['description'];
$doc->url = user_make_link($user_id, 'user');
// module specific information; optional
// construct the parent class
parent::__construct($doc, $data, 0, 0, 0, PATH_FOR_SEARCH_TYPE_USER);
}
}
/**
* a class for representing searchable information in user metadata
*
*/
class UserPostSearchDocument extends SearchDocument {
/**
* constructor
*/
public function __construct(&$post, $user_id, $context_id) {
// generic information; required
$doc->docid = $post['id'];
$doc->documenttype = SEARCH_TYPE_USER;
$doc->itemtype = 'post';
$doc->contextid = $context_id;
$user = get_record('user', 'id', $user_id);
// we cannot call userdate with relevant locale at indexing time.
$doc->title = get_string('post').': '.fullname($user);
$doc->date = $post['created'];
//remove '(ip.ip.ip.ip)' from chat author list
$doc->author = fullname($user);
$doc->contents = $post['description'];
$doc->url = user_make_link($user_id, 'post');
// module specific information; optional
// construct the parent class
parent::__construct($doc, $data, 0, 0, 0, PATH_FOR_SEARCH_TYPE_USER);
}
}
/**
* a class for representing searchable information in user metadata
*
*/
class UserBlogAttachmentSearchDocument extends SearchDocument {
/**
* constructor
*/
public function __construct(&$post, $context_id) {
// generic information; required
$doc->docid = $post['id'];
$doc->documenttype = SEARCH_TYPE_USER;
$doc->itemtype = 'attachment';
$doc->contextid = $context_id;
$user = get_record('user', 'id', $post['userid']);
// we cannot call userdate with relevant locale at indexing time.
$doc->title = get_string('file').' : '.$post['subject'];
$doc->date = $post['created'];
//remove '(ip.ip.ip.ip)' from chat author list
$doc->author = fullname($user);
$doc->contents = $post['alltext'];
$doc->url = user_make_link($post['id'], 'attachment');
// module specific information; optional
// construct the parent class
parent::__construct($doc, $data, 0, 0, 0, PATH_FOR_SEARCH_TYPE_USER);
}
}
/**
* constructs a valid link to a user record
* @param userid the user
* @param itemtype
* @uses CFG
* @return a well formed link to user information
*/
function user_make_link($itemid, $itemtype) {
global $CFG;
if ($itemtype == 'user'){
return $CFG->wwwroot.'/user/view.php?id='.$itemid;
} elseif ($itemtype == 'post') {
return $CFG->wwwroot.'/blog/index.php?userid='.$itemid;
} elseif ($itemtype == 'attachment') {
$post = get_record('post', 'id', $itemid);
if (!$CFG->slasharguments){
return $CFG->wwwroot."/file.php?file=/blog/attachments/{$post->id}/{$post->attachment}";
} else {
return $CFG->wwwroot."/file.php/blog/attachments/{$post->id}/{$post->attachment}";
}
} else {
return null;
}
}
/**
* part of search engine API
*
*/
function user_iterator() {
$users = get_records('user');
return $users;
}
/**
* part of search engine API
* @uses CFG
* @return an array of documents generated from data
*/
function user_get_content_for_index(&$user) {
global $CFG;
$documents = array();
$userhash = get_object_vars($user);
$documents[] = new UserSearchDocument($userhash, $user->id, null);
if ($posts = get_records('post', 'userid', $user->id, 'created')){
foreach($posts as $post){
$texts = array();
$texts[] = $post->subject;
$texts[] = $post->summary;
$texts[] = $post->content;
$post->description = implode(" ", $texts);
// record the attachment if any and physical files can be indexed
if (@$CFG->block_search_enable_file_indexing){
if ($post->attachment){
user_get_physical_file($post, null, false, $documents);
}
}
$posthash = get_object_vars($post);
$documents[] = new UserPostSearchDocument($posthash, $user->id, null);
}
}
return $documents;
}
/**
* get text from a physical file
* @param object $post a post to whech the file is attached to
* @param boolean $context_id if in future we need recording a context along with the search document, pass it here
* @param boolean $getsingle if true, returns a single search document, elsewhere return the array
* given as documents increased by one
* @param array $documents the array of documents, by ref, where to add the new document.
* @return a search document when unique or false.
*/
function user_get_physical_file(&$post, $context_id, $getsingle, &$documents = null){
global $CFG;
// cannot index empty references
if (empty($post->attachment)){
mtrace("Cannot index, empty reference.");
return false;
}
$fileparts = pathinfo($post->attachment);
// cannot index unknown or masked types
if (empty($fileparts['extension'])) {
mtrace("Cannot index without explicit extension.");
return false;
}
// cannot index non existent file
$file = "{$CFG->dataroot}/blog/attachments/{$post->id}/{$post->attachment}";
if (!file_exists($file)){
mtrace("Missing attachment file $file : will not be indexed.");
return false;
}
$ext = strtolower($fileparts['extension']);
// cannot index unallowed or unhandled types
if (!preg_match("/\b$ext\b/i", $CFG->block_search_filetypes)) {
mtrace($fileparts['extension'] . ' is not an allowed extension for indexing');
return false;
}
if (file_exists($CFG->dirroot.'/search/documents/physical_'.$ext.'.php')){
include_once($CFG->dirroot.'/search/documents/physical_'.$ext.'.php');
$function_name = 'get_text_for_indexing_'.$ext;
$directfile = "blog/attachments/{$post->id}/{$post->attachment}";
$post->alltext = $function_name($post, $directfile);
if (!empty($post->alltext)){
if ($getsingle){
$posthash = get_object_vars($post);
$single = new UserBlogAttachmentSearchDocument($posthash, $context_id);
mtrace("finished attachment {$post->attachment} in {$post->title}");
return $single;
} else {
$posthash = get_object_vars($post);
$documents[] = new UserBlogAttachmentSearchDocument($posthash, $context_id);
}
mtrace("finished attachment {$post->attachment} in {$post->subject}");
}
} else {
mtrace("fulltext handler not found for $ext type");
}
return false;
}
/**
* returns a single user search document
* @param composite $id a unique document id made with
* @param itemtype the type of information (session is the only type)
*/
function user_single_document($id, $itemtype) {
if ($itemtype == 'user'){
if ($user = get_record('user', 'id', $id)){
$userhash = get_object_vars($user);
return new UserSearchDocument($userhash, $user->id, 'user', null);
}
} elseif ($itemtype == 'post') {
if ($post = get_records('post', 'id', $id)){
$texts = array();
$texts[] = $post->subject;
$texts[] = $post->summary;
$texts[] = $post->content;
$post->description = implode(" ", $texts);
$posthash = get_object_vars($post);
return new UserPostSearchDocument($posthash, $user->id, 'post', null);
}
} elseif ($itemtype == 'attachment' && @$CFG->block_search_enable_file_indexing) {
if ($post = get_records('post', 'id', $id)){
if ($post->attachment){
return user_get_physical_file($post, null, true);
}
}
}
return null;
}
/**
* dummy delete function that packs id with itemtype.
* this was here for a reason, but I can't remember it at the moment.
*
*/
function user_delete($info, $itemtype) {
$object->id = $info;
$object->itemtype = $itemtype;
return $object;
}
/**
* returns the var names needed to build a sql query for addition/deletions
* attachments are indirect records, linked to its post
*/
function user_db_names() {
//[primary id], [table name], [time created field name], [time modified field name] [itemtype] [select restriction clause]
return array(
array('id', 'user', 'firstaccess', 'timemodified', 'user'),
array('id', 'post', 'created', 'lastmodified', 'post'),
array('id', 'post', 'created', 'lastmodified', 'attachment')
);
}
/**
* this function handles the access policy to contents indexed as searchable documents. If this
* function does not exist, the search engine assumes access is allowed.
* When this point is reached, we already know that :
* - user is legitimate in the surrounding context
* - user may be guest and guest access is allowed to the module
* - the function may perform local checks within the module information logic
* @param path the access path to the module script code
* @param itemtype the information subclassing (usefull for complex modules, defaults to 'standard')
* @param this_id the item id within the information class denoted by entry_type. In chats, this id
* points out a session history which is a close sequence of messages.
* @param user the user record denoting the user who searches
* @param group_id the current group used by the user when searching
* @uses CFG
* @return true if access is allowed, false elsewhere
*/
function user_check_text_access($path, $itemtype, $this_id, $user, $group_id, $context_id){
global $CFG;
include_once("{$CFG->dirroot}/{$path}/lib.php");
if ($itemtype == 'user'){
// get the user
$userrecord = get_record('user', 'id', $this_id);
// we cannot see nothing from unconfirmed users
if (!$userrecord->confirmed and !has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))){
if (!empty($CFG->search_access_debug)) echo "search reject : unconfirmed user ";
return false;
}
} elseif ($itemtype == 'post' || $itemtype == 'attachment'){
// get the post
$post = get_record('post', 'id', $this_id);
$userrecord = get_record('user', 'id', $post->userid);
// we can try using blog visibility check
return blog_user_can_view_user_post($user->id, $post);
}
$context = get_record('context', 'id', $context_id);
return true;
}
/**
* this call back is called when displaying the link for some last post processing
*
*/
function user_link_post_processing($title){
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+7 -2
View File
@@ -50,7 +50,7 @@ class WikiSearchDocument extends SearchDocument {
$data->wiki = $wiki_id;
// construct the parent class
parent::__construct($doc, $data, $course_id, $group_id, $user_id, PATH_FOR_SEARCH_TYPE_WIKI);
parent::__construct($doc, $data, $course_id, $group_id, $user_id, 'mod/'.SEARCH_TYPE_WIKI);
}
}
@@ -268,7 +268,12 @@ function wiki_check_text_access($path, $itemtype, $this_id, $user, $group_id, $c
*
*/
function wiki_link_post_processing($title){
return mb_convert_encoding($title, 'UTF-8', 'auto');
global $CFG;
if ($CFG->block_search_utf8dir){
return mb_convert_encoding($title, 'UTF-8', 'auto');
}
return mb_convert_encoding($title, 'auto', 'UTF-8');
}
?>
+121 -79
View File
@@ -1,106 +1,148 @@
<?php
/* Used to test if modules/blocks are ready to included in the search index.
* Carries out some basic function/file existence tests - the search module
* is expected to exist, along with the db schema files and the search data
* directory.
* */
/* Used to test if modules/blocks are ready to included in the search index.
* Carries out some basic function/file existence tests - the search module
* is expected to exist, along with the db schema files and the search data
* directory.
**/
@set_time_limit(0);
@ob_implicit_flush(true);
@ob_end_flush();
@set_time_limit(0);
@ob_implicit_flush(true);
@ob_end_flush();
require_once('../../config.php');
require_once("$CFG->dirroot/search/lib.php");
require_once('../../config.php');
require_once("$CFG->dirroot/search/lib.php");
require_login();
$strsearch = get_string('search', 'search');
$strquery = get_string('stats');
/// makes inclusions of the Zend Engine more reliable
$separator = (array_key_exists('WINDIR', $_SERVER)) ? ';' : ':' ;
ini_set('include_path', $CFG->dirroot.'\search'.$separator.ini_get('include_path'));
require_login();
$navlinks[] = array('name' => $strsearch, 'link' => "../index.php", 'type' => 'misc');
$navlinks[] = array('name' => $strquery, 'link' => "../stats.php", 'type' => 'misc');
$navlinks[] = array('name' => get_string('runindexertest','search'), 'link' => null, 'type' => 'misc');
$navigation = build_navigation($navlinks);
$site = get_site();
print_header("$strsearch", "$site->fullname" , $navigation, "", "", true, "&nbsp;", navmenu($site));
if (empty($CFG->enableglobalsearch)) {
error('Global searching is not enabled.');
}
if (empty($CFG->enableglobalsearch)) {
error('Global searching is not enabled.');
}
if (!has_capability('moodle/site:doanything', get_context_instance(CONTEXT_SYSTEM))) {
error("You need to be an admin user to use this page.", "$CFG->wwwroot/login/index.php");
} //if
mtrace('<pre>Server Time: '.date('r',time()));
mtrace("Testing global search capabilities:\n");
$phpversion = phpversion();
//fix paths for testing
set_include_path(get_include_path().":../");
require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
mtrace("Checking activity modules:\n");
//the presence of the required search functions -
// * mod_iterator
// * mod_get_content_for_index
//are the sole basis for including a module in the index at the moment.
/// get all installed modules
if ($mods = get_records('modules', '', '', 'name', 'id,name')){
if (!isadmin()) {
error("You need to be an admin user to use this page.", "$CFG->wwwroot/login/index.php");
} //if
$searchabletypes = array_values(search_get_document_types());
mtrace('<pre>Server Time: '.date('r',time()));
mtrace("Testing global search capabilities:\n");
foreach($mods as $mod){
if (in_array($mod->name, $searchabletypes)){
$mod->location = 'internal';
$searchables[] = $mod;
} else {
$documentfile = $CFG->dirroot."/mod/{$mod->name}/search_document.php";
$mod->location = 'mod';
if (file_exists($documentfile)){
$searchables[] = $mod;
}
}
}
mtrace(count($searchables).' modules to search in / '.count($mods).' modules found.');
}
/// collects blocks as indexable information may be found in blocks either
if ($blocks = get_records('block', '', '', 'name', 'id,name')) {
$blocks_searchables = array();
// prepend the "block_" prefix to discriminate document type plugins
foreach($blocks as $block){
$block->dirname = $block->name;
$block->name = 'block_'.$block->name;
if (in_array('SEARCH_TYPE_'.strtoupper($block->name), $searchabletypes)){
$mod->location = 'internal';
$blocks_searchables[] = $block;
} else {
$documentfile = $CFG->dirroot."/blocks/{$block->dirname}/search_document.php";
if (file_exists($documentfile)){
$mod->location = 'blocks';
$blocks_searchables[] = $block;
}
}
}
mtrace(count($blocks_searchables).' blocks to search in / '.count($blocks).' blocks found.');
$searchables = array_merge($searchables, $blocks_searchables);
}
/// add virtual modules onto the back of the array
$phpversion = phpversion();
$additional = search_get_additional_modules();
mtrace(count($additional).' additional to search in.');
$searchables = array_merge($searchables, $additional);
foreach ($searchables as $mod) {
if (!search_check_php5()) {
mtrace("ERROR: PHP 5.0.0 or later required (currently using version $phpversion).");
exit(0);
} else {
mtrace("Success: PHP 5.0.0 or later is installed ($phpversion).\n");
} //else
//fix paths for testing
set_include_path(get_include_path().":../");
require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
mtrace("Checking activity modules:\n");
//the presence of the required search functions -
// * mod_iterator
// * mod_get_content_for_index
//are the sole basis for including a module in the index at the moment.
if ($mods = get_records_select('modules')) {
$mods = array_merge($mods, search_get_additional_modules());
foreach ($mods as $mod) {
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
$key = 'search_in_'.$mod->name;
if (isset($CFG->$key) && !$CFG->$key) {
mtrace("module $key has been administratively disabled. Skipping...\n");
continue;
}
if ($mod->location == 'internal'){
$class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
} else {
$class_file = $CFG->dirroot.'/'.$mod->location.'/'.$mod->name.'/search_document.php';
}
if (file_exists($class_file)) {
include_once($class_file);
if (!defined('SEARCH_TYPE_'.strtoupper($mod->name))) {
mtrace("ERROR: Constant 'SEARCH_TYPE_".strtoupper($mod->name)."' is not defined in /search/lib.php");
if ($mod->location != 'internal' && !defined('X_SEARCH_TYPE_'.strtoupper($mod->name))) {
mtrace("ERROR: Constant 'X_SEARCH_TYPE_".strtoupper($mod->name)."' is not defined in search/searchtypes.php or in module");
continue;
} //if
}
$iter_function = $mod->name.'_iterator';
$index_function = $mod->name.'_get_content_for_index';
if (function_exists($index_function) && function_exists($iter_function)) {
if (is_array($iter_function())) {
$documents = $index_function(array_pop($iter_function()));
$entries = $iter_function();
if (!empty($entries)) {
$documents = $index_function(array_pop($entries));
if (is_array($documents)) {
mtrace("Success: '$mod->name' module seems to be ready for indexing.");
} else {
mtrace("ERROR: $index_function() doesn't seem to be returning an array.");
} //else
}
} else {
mtrace("ERROR: $iter_function() doesn't seem to be returning an object array.");
} //else
mtrace("Success : '$mod->name' has nothing to index.");
}
} else {
mtrace("ERROR: $iter_function() and/or $index_function() does not exist in $class_file");
} //else
}
} else {
mtrace("Notice: $class_file does not exist, this module will not be indexed.");
} //else
} //foreach
} //if
//finished modules
mtrace("\nFinished checking activity modules.");
//now blocks...
//
mtrace("<br/><a href='../index.php'>Back to query page</a> or <a href='../indexersplash.php'>Start indexing</a>.");
mtrace('</pre>');
print_footer();
}
}
//finished modules
mtrace("\nFinished checking activity modules.");
//now blocks...
//
mtrace("<br/><a href='../index.php'>Back to query page</a> or <a href='../indexersplash.php'>Start indexing</a>.");
mtrace('</pre>');
?>