web/lib/Zend/Search/Lucene/Index/SegmentWriter.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Search_Lucene
       
    17  * @subpackage Index
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  * @version    $Id: SegmentWriter.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    21  */
       
    22 
       
    23 
       
    24 /** Zend_Search_Lucene_Index_FieldInfo */
       
    25 require_once 'Zend/Search/Lucene/Index/FieldInfo.php';
       
    26 
       
    27 /** Zend_Search_Lucene_Index_Term */
       
    28 require_once 'Zend/Search/Lucene/Index/Term.php';
       
    29 
       
    30 /** Zend_Search_Lucene_Index_TermInfo */
       
    31 require_once 'Zend/Search/Lucene/Index/TermInfo.php';
       
    32 
       
    33 /**
       
    34  * @category   Zend
       
    35  * @package    Zend_Search_Lucene
       
    36  * @subpackage Index
       
    37  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    38  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    39  */
       
    40 abstract class Zend_Search_Lucene_Index_SegmentWriter
       
    41 {
       
    42     /**
       
    43      * Expert: The fraction of terms in the "dictionary" which should be stored
       
    44      * in RAM.  Smaller values use more memory, but make searching slightly
       
    45      * faster, while larger values use less memory and make searching slightly
       
    46      * slower.  Searching is typically not dominated by dictionary lookup, so
       
    47      * tweaking this is rarely useful.
       
    48      *
       
    49      * @var integer
       
    50      */
       
    51     public static $indexInterval = 128;
       
    52 
       
    53     /**
       
    54      * Expert: The fraction of TermDocs entries stored in skip tables.
       
    55      * Larger values result in smaller indexes, greater acceleration, but fewer
       
    56      * accelerable cases, while smaller values result in bigger indexes,
       
    57      * less acceleration and more
       
    58      * accelerable cases. More detailed experiments would be useful here.
       
    59      *
       
    60      * 0x7FFFFFFF indicates that we don't use skip data
       
    61      *
       
    62      * Note: not used in current implementation
       
    63      *
       
    64      * @var integer
       
    65      */
       
    66     public static $skipInterval = 0x7FFFFFFF;
       
    67 
       
    68     /**
       
    69      * Expert: The maximum number of skip levels. Smaller values result in
       
    70      * slightly smaller indexes, but slower skipping in big posting lists.
       
    71      *
       
    72      * 0 indicates that we don't use skip data
       
    73      *
       
    74      * Note: not used in current implementation
       
    75      *
       
    76      * @var integer
       
    77      */
       
    78     public static $maxSkipLevels = 0;
       
    79 
       
    80     /**
       
    81      * Number of docs in a segment
       
    82      *
       
    83      * @var integer
       
    84      */
       
    85     protected $_docCount = 0;
       
    86 
       
    87     /**
       
    88      * Segment name
       
    89      *
       
    90      * @var string
       
    91      */
       
    92     protected $_name;
       
    93 
       
    94     /**
       
    95      * File system adapter.
       
    96      *
       
    97      * @var Zend_Search_Lucene_Storage_Directory
       
    98      */
       
    99     protected $_directory;
       
   100 
       
   101     /**
       
   102      * List of the index files.
       
   103      * Used for automatic compound file generation
       
   104      *
       
   105      * @var unknown_type
       
   106      */
       
   107     protected $_files = array();
       
   108 
       
   109     /**
       
   110      * Segment fields. Array of Zend_Search_Lucene_Index_FieldInfo objects for this segment
       
   111      *
       
   112      * @var array
       
   113      */
       
   114     protected $_fields = array();
       
   115 
       
   116     /**
       
   117      * Normalization factors.
       
   118      * An array fieldName => normVector
       
   119      * normVector is a binary string.
       
   120      * Each byte corresponds to an indexed document in a segment and
       
   121      * encodes normalization factor (float value, encoded by
       
   122      * Zend_Search_Lucene_Search_Similarity::encodeNorm())
       
   123      *
       
   124      * @var array
       
   125      */
       
   126     protected $_norms = array();
       
   127 
       
   128 
       
   129     /**
       
   130      * '.fdx'  file - Stored Fields, the field index.
       
   131      *
       
   132      * @var Zend_Search_Lucene_Storage_File
       
   133      */
       
   134     protected $_fdxFile = null;
       
   135 
       
   136     /**
       
   137      * '.fdt'  file - Stored Fields, the field data.
       
   138      *
       
   139      * @var Zend_Search_Lucene_Storage_File
       
   140      */
       
   141     protected $_fdtFile = null;
       
   142 
       
   143 
       
   144     /**
       
   145      * Object constructor.
       
   146      *
       
   147      * @param Zend_Search_Lucene_Storage_Directory $directory
       
   148      * @param string $name
       
   149      */
       
   150     public function __construct(Zend_Search_Lucene_Storage_Directory $directory, $name)
       
   151     {
       
   152         $this->_directory = $directory;
       
   153         $this->_name      = $name;
       
   154     }
       
   155 
       
   156 
       
   157     /**
       
   158      * Add field to the segment
       
   159      *
       
   160      * Returns actual field number
       
   161      *
       
   162      * @param Zend_Search_Lucene_Field $field
       
   163      * @return integer
       
   164      */
       
   165     public function addField(Zend_Search_Lucene_Field $field)
       
   166     {
       
   167         if (!isset($this->_fields[$field->name])) {
       
   168             $fieldNumber = count($this->_fields);
       
   169             $this->_fields[$field->name] =
       
   170                                 new Zend_Search_Lucene_Index_FieldInfo($field->name,
       
   171                                                                        $field->isIndexed,
       
   172                                                                        $fieldNumber,
       
   173                                                                        $field->storeTermVector);
       
   174 
       
   175             return $fieldNumber;
       
   176         } else {
       
   177             $this->_fields[$field->name]->isIndexed       |= $field->isIndexed;
       
   178             $this->_fields[$field->name]->storeTermVector |= $field->storeTermVector;
       
   179 
       
   180             return $this->_fields[$field->name]->number;
       
   181         }
       
   182     }
       
   183 
       
   184     /**
       
   185      * Add fieldInfo to the segment
       
   186      *
       
   187      * Returns actual field number
       
   188      *
       
   189      * @param Zend_Search_Lucene_Index_FieldInfo $fieldInfo
       
   190      * @return integer
       
   191      */
       
   192     public function addFieldInfo(Zend_Search_Lucene_Index_FieldInfo $fieldInfo)
       
   193     {
       
   194         if (!isset($this->_fields[$fieldInfo->name])) {
       
   195             $fieldNumber = count($this->_fields);
       
   196             $this->_fields[$fieldInfo->name] =
       
   197                                 new Zend_Search_Lucene_Index_FieldInfo($fieldInfo->name,
       
   198                                                                        $fieldInfo->isIndexed,
       
   199                                                                        $fieldNumber,
       
   200                                                                        $fieldInfo->storeTermVector);
       
   201 
       
   202             return $fieldNumber;
       
   203         } else {
       
   204             $this->_fields[$fieldInfo->name]->isIndexed       |= $fieldInfo->isIndexed;
       
   205             $this->_fields[$fieldInfo->name]->storeTermVector |= $fieldInfo->storeTermVector;
       
   206 
       
   207             return $this->_fields[$fieldInfo->name]->number;
       
   208         }
       
   209     }
       
   210 
       
   211     /**
       
   212      * Returns array of FieldInfo objects.
       
   213      *
       
   214      * @return array
       
   215      */
       
   216     public function getFieldInfos()
       
   217     {
       
   218         return $this->_fields;
       
   219     }
       
   220 
       
   221     /**
       
   222      * Add stored fields information
       
   223      *
       
   224      * @param array $storedFields array of Zend_Search_Lucene_Field objects
       
   225      */
       
   226     public function addStoredFields($storedFields)
       
   227     {
       
   228         if (!isset($this->_fdxFile)) {
       
   229             $this->_fdxFile = $this->_directory->createFile($this->_name . '.fdx');
       
   230             $this->_fdtFile = $this->_directory->createFile($this->_name . '.fdt');
       
   231 
       
   232             $this->_files[] = $this->_name . '.fdx';
       
   233             $this->_files[] = $this->_name . '.fdt';
       
   234         }
       
   235 
       
   236         $this->_fdxFile->writeLong($this->_fdtFile->tell());
       
   237         $this->_fdtFile->writeVInt(count($storedFields));
       
   238         foreach ($storedFields as $field) {
       
   239             $this->_fdtFile->writeVInt($this->_fields[$field->name]->number);
       
   240             $fieldBits = ($field->isTokenized ? 0x01 : 0x00) |
       
   241                          ($field->isBinary ?    0x02 : 0x00) |
       
   242                          0x00; /* 0x04 - third bit, compressed (ZLIB) */
       
   243             $this->_fdtFile->writeByte($fieldBits);
       
   244             if ($field->isBinary) {
       
   245                 $this->_fdtFile->writeVInt(strlen($field->value));
       
   246                 $this->_fdtFile->writeBytes($field->value);
       
   247             } else {
       
   248                 $this->_fdtFile->writeString($field->getUtf8Value());
       
   249             }
       
   250         }
       
   251 
       
   252         $this->_docCount++;
       
   253     }
       
   254 
       
   255     /**
       
   256      * Returns the total number of documents in this segment.
       
   257      *
       
   258      * @return integer
       
   259      */
       
   260     public function count()
       
   261     {
       
   262         return $this->_docCount;
       
   263     }
       
   264 
       
   265     /**
       
   266      * Return segment name
       
   267      *
       
   268      * @return string
       
   269      */
       
   270     public function getName()
       
   271     {
       
   272         return $this->_name;
       
   273     }
       
   274 
       
   275     /**
       
   276      * Dump Field Info (.fnm) segment file
       
   277      */
       
   278     protected function _dumpFNM()
       
   279     {
       
   280         $fnmFile = $this->_directory->createFile($this->_name . '.fnm');
       
   281         $fnmFile->writeVInt(count($this->_fields));
       
   282 
       
   283         $nrmFile = $this->_directory->createFile($this->_name . '.nrm');
       
   284         // Write header
       
   285         $nrmFile->writeBytes('NRM');
       
   286         // Write format specifier
       
   287         $nrmFile->writeByte((int)0xFF);
       
   288 
       
   289         foreach ($this->_fields as $field) {
       
   290             $fnmFile->writeString($field->name);
       
   291             $fnmFile->writeByte(($field->isIndexed       ? 0x01 : 0x00) |
       
   292                                 ($field->storeTermVector ? 0x02 : 0x00)
       
   293 // not supported yet            0x04 /* term positions are stored with the term vectors */ |
       
   294 // not supported yet            0x08 /* term offsets are stored with the term vectors */   |
       
   295                                );
       
   296 
       
   297             if ($field->isIndexed) {
       
   298                 // pre-2.1 index mode (not used now)
       
   299                 // $normFileName = $this->_name . '.f' . $field->number;
       
   300                 // $fFile = $this->_directory->createFile($normFileName);
       
   301                 // $fFile->writeBytes($this->_norms[$field->name]);
       
   302                 // $this->_files[] = $normFileName;
       
   303 
       
   304                 $nrmFile->writeBytes($this->_norms[$field->name]);
       
   305             }
       
   306         }
       
   307 
       
   308         $this->_files[] = $this->_name . '.fnm';
       
   309         $this->_files[] = $this->_name . '.nrm';
       
   310     }
       
   311 
       
   312 
       
   313 
       
   314     /**
       
   315      * Term Dictionary file
       
   316      *
       
   317      * @var Zend_Search_Lucene_Storage_File
       
   318      */
       
   319     private $_tisFile = null;
       
   320 
       
   321     /**
       
   322      * Term Dictionary index file
       
   323      *
       
   324      * @var Zend_Search_Lucene_Storage_File
       
   325      */
       
   326     private $_tiiFile = null;
       
   327 
       
   328     /**
       
   329      * Frequencies file
       
   330      *
       
   331      * @var Zend_Search_Lucene_Storage_File
       
   332      */
       
   333     private $_frqFile = null;
       
   334 
       
   335     /**
       
   336      * Positions file
       
   337      *
       
   338      * @var Zend_Search_Lucene_Storage_File
       
   339      */
       
   340     private $_prxFile = null;
       
   341 
       
   342     /**
       
   343      * Number of written terms
       
   344      *
       
   345      * @var integer
       
   346      */
       
   347     private $_termCount;
       
   348 
       
   349 
       
   350     /**
       
   351      * Last saved term
       
   352      *
       
   353      * @var Zend_Search_Lucene_Index_Term
       
   354      */
       
   355     private $_prevTerm;
       
   356 
       
   357     /**
       
   358      * Last saved term info
       
   359      *
       
   360      * @var Zend_Search_Lucene_Index_TermInfo
       
   361      */
       
   362     private $_prevTermInfo;
       
   363 
       
   364     /**
       
   365      * Last saved index term
       
   366      *
       
   367      * @var Zend_Search_Lucene_Index_Term
       
   368      */
       
   369     private $_prevIndexTerm;
       
   370 
       
   371     /**
       
   372      * Last saved index term info
       
   373      *
       
   374      * @var Zend_Search_Lucene_Index_TermInfo
       
   375      */
       
   376     private $_prevIndexTermInfo;
       
   377 
       
   378     /**
       
   379      * Last term dictionary file position
       
   380      *
       
   381      * @var integer
       
   382      */
       
   383     private $_lastIndexPosition;
       
   384 
       
   385     /**
       
   386      * Create dicrionary, frequency and positions files and write necessary headers
       
   387      */
       
   388     public function initializeDictionaryFiles()
       
   389     {
       
   390         $this->_tisFile = $this->_directory->createFile($this->_name . '.tis');
       
   391         $this->_tisFile->writeInt((int)0xFFFFFFFD);
       
   392         $this->_tisFile->writeLong(0 /* dummy data for terms count */);
       
   393         $this->_tisFile->writeInt(self::$indexInterval);
       
   394         $this->_tisFile->writeInt(self::$skipInterval);
       
   395         $this->_tisFile->writeInt(self::$maxSkipLevels);
       
   396 
       
   397         $this->_tiiFile = $this->_directory->createFile($this->_name . '.tii');
       
   398         $this->_tiiFile->writeInt((int)0xFFFFFFFD);
       
   399         $this->_tiiFile->writeLong(0 /* dummy data for terms count */);
       
   400         $this->_tiiFile->writeInt(self::$indexInterval);
       
   401         $this->_tiiFile->writeInt(self::$skipInterval);
       
   402         $this->_tiiFile->writeInt(self::$maxSkipLevels);
       
   403 
       
   404         /** Dump dictionary header */
       
   405         $this->_tiiFile->writeVInt(0);                    // preffix length
       
   406         $this->_tiiFile->writeString('');                 // suffix
       
   407         $this->_tiiFile->writeInt((int)0xFFFFFFFF);       // field number
       
   408         $this->_tiiFile->writeByte((int)0x0F);
       
   409         $this->_tiiFile->writeVInt(0);                    // DocFreq
       
   410         $this->_tiiFile->writeVInt(0);                    // FreqDelta
       
   411         $this->_tiiFile->writeVInt(0);                    // ProxDelta
       
   412         $this->_tiiFile->writeVInt(24);                   // IndexDelta
       
   413 
       
   414         $this->_frqFile = $this->_directory->createFile($this->_name . '.frq');
       
   415         $this->_prxFile = $this->_directory->createFile($this->_name . '.prx');
       
   416 
       
   417         $this->_files[] = $this->_name . '.tis';
       
   418         $this->_files[] = $this->_name . '.tii';
       
   419         $this->_files[] = $this->_name . '.frq';
       
   420         $this->_files[] = $this->_name . '.prx';
       
   421 
       
   422         $this->_prevTerm          = null;
       
   423         $this->_prevTermInfo      = null;
       
   424         $this->_prevIndexTerm     = null;
       
   425         $this->_prevIndexTermInfo = null;
       
   426         $this->_lastIndexPosition = 24;
       
   427         $this->_termCount         = 0;
       
   428 
       
   429     }
       
   430 
       
   431     /**
       
   432      * Add term
       
   433      *
       
   434      * Term positions is an array( docId => array(pos1, pos2, pos3, ...), ... )
       
   435      *
       
   436      * @param Zend_Search_Lucene_Index_Term $termEntry
       
   437      * @param array $termDocs
       
   438      */
       
   439     public function addTerm($termEntry, $termDocs)
       
   440     {
       
   441         $freqPointer = $this->_frqFile->tell();
       
   442         $proxPointer = $this->_prxFile->tell();
       
   443 
       
   444         $prevDoc = 0;
       
   445         foreach ($termDocs as $docId => $termPositions) {
       
   446             $docDelta = ($docId - $prevDoc)*2;
       
   447             $prevDoc = $docId;
       
   448             if (count($termPositions) > 1) {
       
   449                 $this->_frqFile->writeVInt($docDelta);
       
   450                 $this->_frqFile->writeVInt(count($termPositions));
       
   451             } else {
       
   452                 $this->_frqFile->writeVInt($docDelta + 1);
       
   453             }
       
   454 
       
   455             $prevPosition = 0;
       
   456             foreach ($termPositions as $position) {
       
   457                 $this->_prxFile->writeVInt($position - $prevPosition);
       
   458                 $prevPosition = $position;
       
   459             }
       
   460         }
       
   461 
       
   462         if (count($termDocs) >= self::$skipInterval) {
       
   463             /**
       
   464              * @todo Write Skip Data to a freq file.
       
   465              * It's not used now, but make index more optimal
       
   466              */
       
   467             $skipOffset = $this->_frqFile->tell() - $freqPointer;
       
   468         } else {
       
   469             $skipOffset = 0;
       
   470         }
       
   471 
       
   472         $term = new Zend_Search_Lucene_Index_Term($termEntry->text,
       
   473                                                   $this->_fields[$termEntry->field]->number);
       
   474         $termInfo = new Zend_Search_Lucene_Index_TermInfo(count($termDocs),
       
   475                                                           $freqPointer, $proxPointer, $skipOffset);
       
   476 
       
   477         $this->_dumpTermDictEntry($this->_tisFile, $this->_prevTerm, $term, $this->_prevTermInfo, $termInfo);
       
   478 
       
   479         if (($this->_termCount + 1) % self::$indexInterval == 0) {
       
   480             $this->_dumpTermDictEntry($this->_tiiFile, $this->_prevIndexTerm, $term, $this->_prevIndexTermInfo, $termInfo);
       
   481 
       
   482             $indexPosition = $this->_tisFile->tell();
       
   483             $this->_tiiFile->writeVInt($indexPosition - $this->_lastIndexPosition);
       
   484             $this->_lastIndexPosition = $indexPosition;
       
   485 
       
   486         }
       
   487         $this->_termCount++;
       
   488     }
       
   489 
       
   490     /**
       
   491      * Close dictionary
       
   492      */
       
   493     public function closeDictionaryFiles()
       
   494     {
       
   495         $this->_tisFile->seek(4);
       
   496         $this->_tisFile->writeLong($this->_termCount);
       
   497 
       
   498         $this->_tiiFile->seek(4);
       
   499         // + 1 is used to count an additional special index entry (empty term at the start of the list)
       
   500         $this->_tiiFile->writeLong(($this->_termCount - $this->_termCount % self::$indexInterval)/self::$indexInterval + 1);
       
   501     }
       
   502 
       
   503 
       
   504     /**
       
   505      * Dump Term Dictionary segment file entry.
       
   506      * Used to write entry to .tis or .tii files
       
   507      *
       
   508      * @param Zend_Search_Lucene_Storage_File $dicFile
       
   509      * @param Zend_Search_Lucene_Index_Term $prevTerm
       
   510      * @param Zend_Search_Lucene_Index_Term $term
       
   511      * @param Zend_Search_Lucene_Index_TermInfo $prevTermInfo
       
   512      * @param Zend_Search_Lucene_Index_TermInfo $termInfo
       
   513      */
       
   514     protected function _dumpTermDictEntry(Zend_Search_Lucene_Storage_File $dicFile,
       
   515                                         &$prevTerm,     Zend_Search_Lucene_Index_Term     $term,
       
   516                                         &$prevTermInfo, Zend_Search_Lucene_Index_TermInfo $termInfo)
       
   517     {
       
   518         if (isset($prevTerm) && $prevTerm->field == $term->field) {
       
   519             $matchedBytes = 0;
       
   520             $maxBytes = min(strlen($prevTerm->text), strlen($term->text));
       
   521             while ($matchedBytes < $maxBytes  &&
       
   522                    $prevTerm->text[$matchedBytes] == $term->text[$matchedBytes]) {
       
   523                 $matchedBytes++;
       
   524             }
       
   525 
       
   526             // Calculate actual matched UTF-8 pattern
       
   527             $prefixBytes = 0;
       
   528             $prefixChars = 0;
       
   529             while ($prefixBytes < $matchedBytes) {
       
   530                 $charBytes = 1;
       
   531                 if ((ord($term->text[$prefixBytes]) & 0xC0) == 0xC0) {
       
   532                     $charBytes++;
       
   533                     if (ord($term->text[$prefixBytes]) & 0x20 ) {
       
   534                         $charBytes++;
       
   535                         if (ord($term->text[$prefixBytes]) & 0x10 ) {
       
   536                             $charBytes++;
       
   537                         }
       
   538                     }
       
   539                 }
       
   540 
       
   541                 if ($prefixBytes + $charBytes > $matchedBytes) {
       
   542                     // char crosses matched bytes boundary
       
   543                     // skip char
       
   544                     break;
       
   545                 }
       
   546 
       
   547                 $prefixChars++;
       
   548                 $prefixBytes += $charBytes;
       
   549             }
       
   550 
       
   551             // Write preffix length
       
   552             $dicFile->writeVInt($prefixChars);
       
   553             // Write suffix
       
   554             $dicFile->writeString(substr($term->text, $prefixBytes));
       
   555         } else {
       
   556             // Write preffix length
       
   557             $dicFile->writeVInt(0);
       
   558             // Write suffix
       
   559             $dicFile->writeString($term->text);
       
   560         }
       
   561         // Write field number
       
   562         $dicFile->writeVInt($term->field);
       
   563         // DocFreq (the count of documents which contain the term)
       
   564         $dicFile->writeVInt($termInfo->docFreq);
       
   565 
       
   566         $prevTerm = $term;
       
   567 
       
   568         if (!isset($prevTermInfo)) {
       
   569             // Write FreqDelta
       
   570             $dicFile->writeVInt($termInfo->freqPointer);
       
   571             // Write ProxDelta
       
   572             $dicFile->writeVInt($termInfo->proxPointer);
       
   573         } else {
       
   574             // Write FreqDelta
       
   575             $dicFile->writeVInt($termInfo->freqPointer - $prevTermInfo->freqPointer);
       
   576             // Write ProxDelta
       
   577             $dicFile->writeVInt($termInfo->proxPointer - $prevTermInfo->proxPointer);
       
   578         }
       
   579         // Write SkipOffset - it's not 0 when $termInfo->docFreq > self::$skipInterval
       
   580         if ($termInfo->skipOffset != 0) {
       
   581             $dicFile->writeVInt($termInfo->skipOffset);
       
   582         }
       
   583 
       
   584         $prevTermInfo = $termInfo;
       
   585     }
       
   586 
       
   587 
       
   588     /**
       
   589      * Generate compound index file
       
   590      */
       
   591     protected function _generateCFS()
       
   592     {
       
   593         $cfsFile = $this->_directory->createFile($this->_name . '.cfs');
       
   594         $cfsFile->writeVInt(count($this->_files));
       
   595 
       
   596         $dataOffsetPointers = array();
       
   597         foreach ($this->_files as $fileName) {
       
   598             $dataOffsetPointers[$fileName] = $cfsFile->tell();
       
   599             $cfsFile->writeLong(0); // write dummy data
       
   600             $cfsFile->writeString($fileName);
       
   601         }
       
   602 
       
   603         foreach ($this->_files as $fileName) {
       
   604             // Get actual data offset
       
   605             $dataOffset = $cfsFile->tell();
       
   606             // Seek to the data offset pointer
       
   607             $cfsFile->seek($dataOffsetPointers[$fileName]);
       
   608             // Write actual data offset value
       
   609             $cfsFile->writeLong($dataOffset);
       
   610             // Seek back to the end of file
       
   611             $cfsFile->seek($dataOffset);
       
   612 
       
   613             $dataFile = $this->_directory->getFileObject($fileName);
       
   614 
       
   615             $byteCount = $this->_directory->fileLength($fileName);
       
   616             while ($byteCount > 0) {
       
   617                 $data = $dataFile->readBytes(min($byteCount, 131072 /*128Kb*/));
       
   618                 $byteCount -= strlen($data);
       
   619                 $cfsFile->writeBytes($data);
       
   620             }
       
   621 
       
   622             $this->_directory->deleteFile($fileName);
       
   623         }
       
   624     }
       
   625 
       
   626 
       
   627     /**
       
   628      * Close segment, write it to disk and return segment info
       
   629      *
       
   630      * @return Zend_Search_Lucene_Index_SegmentInfo
       
   631      */
       
   632     abstract public function close();
       
   633 }
       
   634