Source for file indexer.php

Documentation is available at indexer.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Administrator
  4.  * @subpackage  com_finder
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('_JEXEC'or die;
  11.  
  12. JLoader::register('FinderIndexerHelper'__DIR__ . '/helper.php');
  13. JLoader::register('FinderIndexerParser'__DIR__ . '/parser.php');
  14. JLoader::register('FinderIndexerStemmer'__DIR__ . '/stemmer.php');
  15. JLoader::register('FinderIndexerTaxonomy'__DIR__ . '/taxonomy.php');
  16. JLoader::register('FinderIndexerToken'__DIR__ . '/token.php');
  17.  
  18. jimport('joomla.filesystem.file');
  19.  
  20. /**
  21.  * Main indexer class for the Finder indexer package.
  22.  *
  23.  * The indexer class provides the core functionality of the Finder
  24.  * search engine. It is responsible for adding and updating the
  25.  * content links table; extracting and scoring tokens; and maintaining
  26.  * all referential information for the content.
  27.  *
  28.  * Note: All exceptions thrown from within this class should be caught
  29.  * by the controller.
  30.  *
  31.  * @package     Joomla.Administrator
  32.  * @subpackage  com_finder
  33.  * @since       2.5
  34.  */
  35. abstract class FinderIndexer
  36. {
  37.     /**
  38.      * The title context identifier.
  39.      *
  40.      * @var    integer 
  41.      * @since  2.5
  42.      */
  43.     const TITLE_CONTEXT 1;
  44.  
  45.     /**
  46.      * The text context identifier.
  47.      *
  48.      * @var    integer 
  49.      * @since  2.5
  50.      */
  51.     const TEXT_CONTEXT 2;
  52.  
  53.     /**
  54.      * The meta context identifier.
  55.      *
  56.      * @var    integer 
  57.      * @since  2.5
  58.      */
  59.     const META_CONTEXT 3;
  60.  
  61.     /**
  62.      * The path context identifier.
  63.      *
  64.      * @var    integer 
  65.      * @since  2.5
  66.      */
  67.     const PATH_CONTEXT 4;
  68.  
  69.     /**
  70.      * The misc context identifier.
  71.      *
  72.      * @var    integer 
  73.      * @since  2.5
  74.      */
  75.     const MISC_CONTEXT 5;
  76.  
  77.     /**
  78.      * The indexer state object.
  79.      *
  80.      * @var    object 
  81.      * @since  2.5
  82.      */
  83.     public static $state;
  84.  
  85.     /**
  86.      * The indexer profiler object.
  87.      *
  88.      * @var    object 
  89.      * @since  2.5
  90.      */
  91.     public static $profiler;
  92.  
  93.     /**
  94.      * Returns a reference to the FinderIndexer object.
  95.      *
  96.      * @return  FinderIndexer instance based on the database driver
  97.      *
  98.      * @since   3.0
  99.      * @throws  RuntimeException if driver class for indexer not present.
  100.      */
  101.     public static function getInstance()
  102.     {
  103.         // Setup the adapter for the indexer.
  104.         $format JFactory::getDbo()->name;
  105.  
  106.         if ($format == 'mysqli')
  107.         {
  108.             $format 'mysql';
  109.         }
  110.         elseif ($format == 'sqlazure')
  111.         {
  112.             $format 'sqlsrv';
  113.         }
  114.         $path = __DIR__ . '/driver/' $format '.php';
  115.         $class 'FinderIndexerDriver' ucfirst($format);
  116.  
  117.         // Check if a parser exists for the format.
  118.         if (file_exists($path))
  119.         {
  120.             // Instantiate the parser.
  121.             include_once $path;
  122.             return new $class;
  123.         }
  124.         else
  125.         {
  126.             // Throw invalid format exception.
  127.             throw new RuntimeException(JText::sprintf('COM_FINDER_INDEXER_INVALID_DRIVER'$format));
  128.         }
  129.     }
  130.  
  131.     /**
  132.      * Method to get the indexer state.
  133.      *
  134.      * @return  object  The indexer state object.
  135.      *
  136.      * @since   2.5
  137.      */
  138.     public static function getState()
  139.     {
  140.         // First, try to load from the internal state.
  141.         if (!empty(self::$state))
  142.         {
  143.             return self::$state;
  144.         }
  145.  
  146.         // If we couldn't load from the internal state, try the session.
  147.         $session JFactory::getSession();
  148.         $data $session->get('_finder.state'null);
  149.  
  150.         // If the state is empty, load the values for the first time.
  151.         if (empty($data))
  152.         {
  153.             $data new JObject;
  154.  
  155.             // Load the default configuration options.
  156.             $data->options JComponentHelper::getParams('com_finder');
  157.  
  158.             // Setup the weight lookup information.
  159.             $data->weights array(
  160.                 self::TITLE_CONTEXT    => round($data->options->get('title_multiplier'1.7)2),
  161.                 self::TEXT_CONTEXT    => round($data->options->get('text_multiplier'0.7)2),
  162.                 self::META_CONTEXT    => round($data->options->get('meta_multiplier'1.2)2),
  163.                 self::PATH_CONTEXT    => round($data->options->get('path_multiplier'2.0)2),
  164.                 self::MISC_CONTEXT    => round($data->options->get('misc_multiplier'0.3)2)
  165.             );
  166.  
  167.             // Set the current time as the start time.
  168.             $data->startTime JFactory::getDate()->toSQL();
  169.  
  170.             // Set the remaining default values.
  171.             $data->batchSize = (int) $data->options->get('batch_size'50);
  172.             $data->batchOffset 0;
  173.             $data->totalItems 0;
  174.             $data->pluginState array();
  175.         }
  176.  
  177.         // Setup the profiler if debugging is enabled.
  178.         if (JFactory::getApplication()->getCfg('debug'))
  179.         {
  180.             self::$profiler JProfiler::getInstance('FinderIndexer');
  181.         }
  182.  
  183.         // Setup the stemmer.
  184.         if ($data->options->get('stem'1&& $data->options->get('stemmer''porter_en'))
  185.         {
  186.             FinderIndexerHelper::$stemmer FinderIndexerStemmer::getInstance($data->options->get('stemmer''porter_en'));
  187.         }
  188.  
  189.         // Set the state.
  190.         self::$state $data;
  191.  
  192.         return self::$state;
  193.     }
  194.  
  195.     /**
  196.      * Method to set the indexer state.
  197.      *
  198.      * @param   object  $data  A new indexer state object.
  199.      *
  200.      * @return  boolean  True on success, false on failure.
  201.      *
  202.      * @since   2.5
  203.      */
  204.     public static function setState($data)
  205.     {
  206.         // Check the state object.
  207.         if (empty($data|| !$data instanceof JObject)
  208.         {
  209.             return false;
  210.         }
  211.  
  212.         // Set the new internal state.
  213.         self::$state $data;
  214.  
  215.         // Set the new session state.
  216.         $session JFactory::getSession();
  217.         $session->set('_finder.state'$data);
  218.  
  219.         return true;
  220.     }
  221.  
  222.     /**
  223.      * Method to reset the indexer state.
  224.      *
  225.      * @return  void 
  226.      *
  227.      * @since   2.5
  228.      */
  229.     public static function resetState()
  230.     {
  231.         // Reset the internal state to null.
  232.         self::$state null;
  233.  
  234.         // Reset the session state to null.
  235.         $session JFactory::getSession();
  236.         $session->set('_finder.state'null);
  237.     }
  238.  
  239.     /**
  240.      * Method to index a content item.
  241.      *
  242.      * @param   FinderIndexerResult  $item    The content item to index.
  243.      * @param   string               $format  The format of the content. [optional]
  244.      *
  245.      * @return  integer  The ID of the record in the links table.
  246.      *
  247.      * @since   2.5
  248.      * @throws  Exception on database error.
  249.      */
  250.     abstract public function index($item$format 'html');
  251.  
  252.     /**
  253.      * Method to remove a link from the index.
  254.      *
  255.      * @param   integer  $linkId  The id of the link.
  256.      *
  257.      * @return  boolean  True on success.
  258.      *
  259.      * @since   2.5
  260.      * @throws  Exception on database error.
  261.      */
  262.     abstract public function remove($linkId);
  263.  
  264.     /**
  265.      * Method to optimize the index. We use this method to remove unused terms
  266.      * and any other optimizations that might be necessary.
  267.      *
  268.      * @return  boolean  True on success.
  269.      *
  270.      * @since   2.5
  271.      * @throws  Exception on database error.
  272.      */
  273.     abstract public function optimize();
  274.  
  275.     /**
  276.      * Method to get a content item's signature.
  277.      *
  278.      * @param   object  $item  The content item to index.
  279.      *
  280.      * @return  string  The content item's signature.
  281.      *
  282.      * @since   2.5
  283.      */
  284.     protected static function getSignature($item)
  285.     {
  286.         // Get the indexer state.
  287.         $state self::getState();
  288.  
  289.         // Get the relevant configuration variables.
  290.         $config array();
  291.         $config[$state->weights;
  292.         $config[$state->options->get('stem'1);
  293.         $config[$state->options->get('stemmer''porter_en');
  294.  
  295.         return md5(serialize(array($item$config)));
  296.     }
  297.  
  298.     /**
  299.      * Method to parse input, tokenize it, and then add it to the database.
  300.      *
  301.      * @param   mixed    $input    String or resource to use as input. A resource
  302.      *                              input will automatically be chunked to conserve
  303.      *                              memory. Strings will be chunked if longer than
  304.      *                              2K in size.
  305.      * @param   integer  $context  The context of the input. See context constants.
  306.      * @param   string   $lang     The language of the input.
  307.      * @param   string   $format   The format of the input.
  308.      *
  309.      * @return  integer  The number of tokens extracted from the input.
  310.      *
  311.      * @since   2.5
  312.      */
  313.     protected function tokenizeToDB($input$context$lang$format)
  314.     {
  315.         $count 0;
  316.         $buffer null;
  317.  
  318.         if (!empty($input))
  319.         {
  320.             // If the input is a resource, batch the process out.
  321.             if (is_resource($input))
  322.             {
  323.                 // Batch the process out to avoid memory limits.
  324.                 while (!feof($input))
  325.                 {
  326.                     // Read into the buffer.
  327.                     $buffer .= fread($input2048);
  328.  
  329.                     /*
  330.                      * If we haven't reached the end of the file, seek to the last
  331.                      * space character and drop whatever is after that to make sure
  332.                      * we didn't truncate a term while reading the input.
  333.                      */
  334.                     if (!feof($input))
  335.                     {
  336.                         // Find the last space character.
  337.                         $ls strrpos($buffer' ');
  338.  
  339.                         // Adjust string based on the last space character.
  340.                         if ($ls)
  341.                         {
  342.                             // Truncate the string to the last space character.
  343.                             $string substr($buffer0$ls);
  344.  
  345.                             // Adjust the buffer based on the last space for the next iteration and trim.
  346.                             $buffer JString::trim(substr($buffer$ls));
  347.                         }
  348.                         // No space character was found.
  349.                         else
  350.                         {
  351.                             $string $buffer;
  352.                         }
  353.                     }
  354.                     // We've reached the end of the file, so parse whatever remains.
  355.                     else
  356.                     {
  357.                         $string $buffer;
  358.                     }
  359.  
  360.                     // Parse the input.
  361.                     $string FinderIndexerHelper::parse($string$format);
  362.  
  363.                     // Check the input.
  364.                     if (empty($string))
  365.                     {
  366.                         continue;
  367.                     }
  368.  
  369.                     // Tokenize the input.
  370.                     $tokens FinderIndexerHelper::tokenize($string$lang);
  371.  
  372.                     // Add the tokens to the database.
  373.                     $count += $this->addTokensToDB($tokens$context);
  374.  
  375.                     // Check if we're approaching the memory limit of the token table.
  376.                     if ($count self::$state->options->get('memory_table_limit'30000))
  377.                     {
  378.                         $this->toggleTables(false);
  379.                     }
  380.  
  381.                     unset($string);
  382.                     unset($tokens);
  383.                 }
  384.             }
  385.             // If the input is greater than 2K in size, it is more efficient to
  386.             // batch out the operation into smaller chunks of work.
  387.             elseif (strlen($input2048)
  388.             {
  389.                 $start 0;
  390.                 $end strlen($input);
  391.                 $chunk 2048;
  392.  
  393.                 /*
  394.                  * As it turns out, the complex regular expressions we use for
  395.                  * sanitizing input are not very efficient when given large
  396.                  * strings. It is much faster to process lots of short strings.
  397.                  */
  398.                 while ($start $end)
  399.                 {
  400.                     // Setup the string.
  401.                     $string substr($input$start$chunk);
  402.  
  403.                     // Find the last space character if we aren't at the end.
  404.                     $ls (($start $chunk$end strrpos($string' 'false);
  405.  
  406.                     // Truncate to the last space character.
  407.                     if ($ls !== false)
  408.                     {
  409.                         $string substr($string0$ls);
  410.                     }
  411.  
  412.                     // Adjust the start position for the next iteration.
  413.                     $start += ($ls !== false ($ls $chunk$chunk $chunk);
  414.  
  415.                     // Parse the input.
  416.                     $string FinderIndexerHelper::parse($string$format);
  417.  
  418.                     // Check the input.
  419.                     if (empty($string))
  420.                     {
  421.                         continue;
  422.                     }
  423.  
  424.                     // Tokenize the input.
  425.                     $tokens FinderIndexerHelper::tokenize($string$lang);
  426.  
  427.                     // Add the tokens to the database.
  428.                     $count += $this->addTokensToDB($tokens$context);
  429.  
  430.                     // Check if we're approaching the memory limit of the token table.
  431.                     if ($count self::$state->options->get('memory_table_limit'30000))
  432.                     {
  433.                         $this->toggleTables(false);
  434.                     }
  435.                 }
  436.             }
  437.             else
  438.             {
  439.                 // Parse the input.
  440.                 $input FinderIndexerHelper::parse($input$format);
  441.  
  442.                 // Check the input.
  443.                 if (empty($input))
  444.                 {
  445.                     return $count;
  446.                 }
  447.  
  448.                 // Tokenize the input.
  449.                 $tokens FinderIndexerHelper::tokenize($input$lang);
  450.  
  451.                 // Add the tokens to the database.
  452.                 $count $this->addTokensToDB($tokens$context);
  453.             }
  454.         }
  455.  
  456.         return $count;
  457.     }
  458.  
  459.     /**
  460.      * Method to add a set of tokens to the database.
  461.      *
  462.      * @param   mixed  $tokens   An array or single FinderIndexerToken object.
  463.      * @param   mixed  $context  The context of the tokens. See context constants. [optional]
  464.      *
  465.      * @return  integer  The number of tokens inserted into the database.
  466.      *
  467.      * @since   2.5
  468.      * @throws  Exception on database error.
  469.      */
  470.     abstract protected function addTokensToDB($tokens$context '');
  471.  
  472.     /**
  473.      * Method to switch the token tables from Memory tables to MyISAM tables
  474.      * when they are close to running out of memory.
  475.      *
  476.      * @param   boolean  $memory  Flag to control how they should be toggled.
  477.      *
  478.      * @return  boolean  True on success.
  479.      *
  480.      * @since   2.5
  481.      * @throws  Exception on database error.
  482.      */
  483.     abstract protected function toggleTables($memory);
  484. }

Documentation generated on Tue, 19 Nov 2013 15:05:31 +0100 by phpDocumentor 1.4.3