File indexing completed on 2024-06-23 05:55:43

0001 <?php
0002 
0003 /**
0004  * Copyright (c) 2007-2011, Servigistics, Inc.
0005  * All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions are met:
0009  *
0010  *  - Redistributions of source code must retain the above copyright notice,
0011  *    this list of conditions and the following disclaimer.
0012  *  - Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  *  - Neither the name of Servigistics, Inc. nor the names of
0016  *    its contributors may be used to endorse or promote products derived from
0017  *    this software without specific prior written permission.
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0020  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0022  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0023  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0024  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0025  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0026  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0027  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0028  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0029  * POSSIBILITY OF SUCH DAMAGE.
0030  *
0031  * @copyright Copyright 2007-2011 Servigistics, Inc. (http://servigistics.com)
0032  * @license http://solr-php-client.googlecode.com/svn/trunk/COPYING New BSD
0033  * @version $Id: Balancer.php 54 2011-02-04 16:29:18Z donovan.jimenez $
0034  *
0035  * @package Apache
0036  * @subpackage Solr
0037  * @author Donovan Jimenez <djimenez@conduit-it.com>, Dan Wolfe
0038  */
0039 require_once 'Zend/Service/Solr/Service.php';
0040 require_once 'Zend/Service/Solr/NoServiceAvailableException.php';
0041 
0042 /**
0043  * Reference Implementation for using multiple Solr services in a distribution. Functionality
0044  * includes:
0045  *  routing of read / write operations
0046  *  failover (on selection) for multiple read servers
0047  */
0048 class Zend_Service_Solr_Service_Balancer {
0049     /**
0050      * SVN Revision meta data for this class
0051      */
0052     const SVN_REVISION = '$Revision: 54 $';
0053 
0054     /**
0055      * SVN ID meta data for this class
0056      */
0057     const SVN_ID = '$Id: Balancer.php 54 2011-02-04 16:29:18Z donovan.jimenez $';
0058 
0059     protected $_createDocuments = true;
0060     protected $_readableServices = array();
0061     protected $_writeableServices = array();
0062     protected $_currentReadService = null;
0063     protected $_currentWriteService = null;
0064     protected $_readPingTimeout = 2;
0065     protected $_writePingTimeout = 4;
0066     // Configuration for server selection backoff intervals
0067     protected $_useBackoff = false;  // Set to true to use more resillient write server selection
0068     protected $_backoffLimit = 600;  // 10 minute default maximum
0069     protected $_backoffEscalation = 2.0;  // Rate at which to increase backoff period
0070     protected $_defaultBackoff = 2.0;  // Default backoff interval
0071 
0072     /**
0073      * Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
0074      *
0075      * NOTE: inside a phrase fewer characters need escaped, use {@link Zend_Service_Solr_Service::escapePhrase()} instead
0076      *
0077      * @param string $value
0078      * @return string
0079      */
0080 
0081     static public function escape($value) {
0082         return Zend_Service_Solr_Service::escape($value);
0083     }
0084 
0085     /**
0086      * Escape a value meant to be contained in a phrase for special query characters
0087      *
0088      * @param string $value
0089      * @return string
0090      */
0091     static public function escapePhrase($value) {
0092         return Zend_Service_Solr_Service::escapePhrase($value);
0093     }
0094 
0095     /**
0096      * Convenience function for creating phrase syntax from a value
0097      *
0098      * @param string $value
0099      * @return string
0100      */
0101     static public function phrase($value) {
0102         return Zend_Service_Solr_Service::phrase($value);
0103     }
0104 
0105     /**
0106      * Constructor. Takes arrays of read and write service instances or descriptions
0107      *
0108      * @param array $readableServices
0109      * @param array $writeableServices
0110      */
0111     public function __construct($readableServices = array(), $writeableServices = array()) {
0112         //setup readable services
0113         foreach ($readableServices as $service) {
0114             $this->addReadService($service);
0115         }
0116 
0117         //setup writeable services
0118         foreach ($writeableServices as $service) {
0119             $this->addWriteService($service);
0120         }
0121     }
0122 
0123     public function setReadPingTimeout($timeout) {
0124         $this->_readPingTimeout = $timeout;
0125     }
0126 
0127     public function setWritePingTimeout($timeout) {
0128         $this->_writePingTimeout = $timeout;
0129     }
0130 
0131     public function setUseBackoff($enable) {
0132         $this->_useBackoff = $enable;
0133     }
0134 
0135     /**
0136      * Generates a service ID
0137      *
0138      * @param string $host
0139      * @param integer $port
0140      * @param string $path
0141      * @return string
0142      */
0143     protected function _getServiceId($host, $port, $path) {
0144         return $host . ':' . $port . $path;
0145     }
0146 
0147     /**
0148      * Adds a service instance or service descriptor (if it is already
0149      * not added)
0150      *
0151      * @param mixed $service
0152      *
0153      * @throws Zend_Service_Solr_InvalidArgumentException If service descriptor is not valid
0154      */
0155     public function addReadService($service) {
0156         if ($service instanceof Zend_Service_Solr_Service) {
0157             $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
0158 
0159             $this->_readableServices[$id] = $service;
0160         } else if (is_array($service)) {
0161             if (isset($service['host']) && isset($service['port']) && isset($service['path'])) {
0162                 $id = $this->_getServiceId((string) $service['host'], (int) $service['port'], (string) $service['path']);
0163 
0164                 $this->_readableServices[$id] = $service;
0165             } else {
0166                 throw new Zend_Service_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path');
0167             }
0168         }
0169     }
0170 
0171     /**
0172      * Removes a service instance or descriptor from the available services
0173      *
0174      * @param mixed $service
0175      *
0176      * @throws Zend_Service_Solr_InvalidArgumentException If service descriptor is not valid
0177      */
0178     public function removeReadService($service) {
0179         $id = '';
0180 
0181         if ($service instanceof Zend_Service_Solr_Service) {
0182             $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
0183         } else if (is_array($service)) {
0184             if (isset($service['host']) && isset($service['port']) && isset($service['path'])) {
0185                 $id = $this->_getServiceId((string) $service['host'], (int) $service['port'], (string) $service['path']);
0186             } else {
0187                 throw new Zend_Service_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path');
0188             }
0189         } else if (is_string($service)) {
0190             $id = $service;
0191         }
0192 
0193         if ($id && isset($this->_readableServices[$id])) {
0194             unset($this->_readableServices[$id]);
0195         }
0196     }
0197 
0198     /**
0199      * Adds a service instance or service descriptor (if it is already
0200      * not added)
0201      *
0202      * @param mixed $service
0203      *
0204      * @throws Zend_Service_Solr_InvalidArgumentException If service descriptor is not valid
0205      */
0206     public function addWriteService($service) {
0207         if ($service instanceof Zend_Service_Solr_Service) {
0208             $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
0209 
0210             $this->_writeableServices[$id] = $service;
0211         } else if (is_array($service)) {
0212             if (isset($service['host']) && isset($service['port']) && isset($service['path'])) {
0213                 $id = $this->_getServiceId((string) $service['host'], (int) $service['port'], (string) $service['path']);
0214 
0215                 $this->_writeableServices[$id] = $service;
0216             } else {
0217                 throw new Zend_Service_Solr_InvalidArgumentException('A Writeable Service description array does not have all required elements of host, port, and path');
0218             }
0219         }
0220     }
0221 
0222     /**
0223      * Removes a service instance or descriptor from the available services
0224      *
0225      * @param mixed $service
0226      *
0227      * @throws Zend_Service_Solr_InvalidArgumentException If service descriptor is not valid
0228      */
0229     public function removeWriteService($service) {
0230         $id = '';
0231 
0232         if ($service instanceof Zend_Service_Solr_Service) {
0233             $id = $this->_getServiceId($service->getHost(), $service->getPort(), $service->getPath());
0234         } else if (is_array($service)) {
0235             if (isset($service['host']) && isset($service['port']) && isset($service['path'])) {
0236                 $id = $this->_getServiceId((string) $service['host'], (int) $service['port'], (string) $service['path']);
0237             } else {
0238                 throw new Zend_Service_Solr_InvalidArgumentException('A Readable Service description array does not have all required elements of host, port, and path');
0239             }
0240         } else if (is_string($service)) {
0241             $id = $service;
0242         }
0243 
0244         if ($id && isset($this->_writeableServices[$id])) {
0245             unset($this->_writeableServices[$id]);
0246         }
0247     }
0248 
0249     /**
0250      * Iterate through available read services and select the first with a ping
0251      * that satisfies configured timeout restrictions (or the default)
0252      *
0253      * @return Zend_Service_Solr_Service
0254      *
0255      * @throws Zend_Service_Solr_NoServiceAvailableException If there are no read services that meet requirements
0256      */
0257     protected function _selectReadService($forceSelect = false) {
0258         if (!$this->_currentReadService || !isset($this->_readableServices[$this->_currentReadService]) || $forceSelect) {
0259             if ($this->_currentReadService && isset($this->_readableServices[$this->_currentReadService]) && $forceSelect) {
0260                 // we probably had a communication error, ping the current read service, remove it if it times out
0261                 if ($this->_readableServices[$this->_currentReadService]->ping($this->_readPingTimeout) === false) {
0262                     $this->removeReadService($this->_currentReadService);
0263                 }
0264             }
0265 
0266             if (count($this->_readableServices)) {
0267                 // select one of the read services at random
0268                 $ids = array_keys($this->_readableServices);
0269 
0270                 $id = $ids[rand(0, count($ids) - 1)];
0271                 $service = $this->_readableServices[$id];
0272 
0273                 if (is_array($service)) {
0274                     //convert the array definition to a client object
0275                     $service = new Zend_Service_Solr_Service($service['host'], $service['port'], $service['path']);
0276                     $this->_readableServices[$id] = $service;
0277                 }
0278 
0279                 $service->setCreateDocuments($this->_createDocuments);
0280                 $this->_currentReadService = $id;
0281             } else {
0282                 throw new Zend_Service_Solr_NoServiceAvailableException('No read services were available');
0283             }
0284         }
0285 
0286         return $this->_readableServices[$this->_currentReadService];
0287     }
0288 
0289     /**
0290      * Iterate through available write services and select the first with a ping
0291      * that satisfies configured timeout restrictions (or the default)
0292      *
0293      * @return Zend_Service_Solr_Service
0294      *
0295      * @throws Zend_Service_Solr_NoServiceAvailableException If there are no write services that meet requirements
0296      */
0297     protected function _selectWriteService($forceSelect = false) {
0298         if ($this->_useBackoff) {
0299             return $this->_selectWriteServiceSafe($forceSelect);
0300         }
0301 
0302         if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect) {
0303             if ($this->_currentWriteService && isset($this->_writeableServices[$this->_currentWriteService]) && $forceSelect) {
0304                 // we probably had a communication error, ping the current read service, remove it if it times out
0305                 if ($this->_writeableServices[$this->_currentWriteService]->ping($this->_writePingTimeout) === false) {
0306                     $this->removeWriteService($this->_currentWriteService);
0307                 }
0308             }
0309 
0310             if (count($this->_writeableServices)) {
0311                 // select one of the read services at random
0312                 $ids = array_keys($this->_writeableServices);
0313 
0314                 $id = $ids[rand(0, count($ids) - 1)];
0315                 $service = $this->_writeableServices[$id];
0316 
0317                 if (is_array($service)) {
0318                     //convert the array definition to a client object
0319                     $service = new Zend_Service_Solr_Service($service['host'], $service['port'], $service['path']);
0320                     $this->_writeableServices[$id] = $service;
0321                 }
0322 
0323                 $this->_currentWriteService = $id;
0324             } else {
0325                 throw new Zend_Service_Solr_NoServiceAvailableException('No write services were available');
0326             }
0327         }
0328 
0329         return $this->_writeableServices[$this->_currentWriteService];
0330     }
0331 
0332     /**
0333      * Iterate through available write services and select the first with a ping
0334      * that satisfies configured timeout restrictions (or the default).  The
0335      * timeout period will increase until a connection is made or the limit is
0336      * reached.   This will allow for increased reliability with heavily loaded
0337      * server(s).
0338      *
0339      * @return Zend_Service_Solr_Service
0340      *
0341      * @throws Zend_Service_Solr_NoServiceAvailableException If there are no write services that meet requirements
0342      */
0343     protected function _selectWriteServiceSafe($forceSelect = false) {
0344         if (!$this->_currentWriteService || !isset($this->_writeableServices[$this->_currentWriteService]) || $forceSelect) {
0345             if (count($this->_writeableServices)) {
0346                 $backoff = $this->_defaultBackoff;
0347 
0348                 do {
0349                     // select one of the read services at random
0350                     $ids = array_keys($this->_writeableServices);
0351 
0352                     $id = $ids[rand(0, count($ids) - 1)];
0353                     $service = $this->_writeableServices[$id];
0354 
0355                     if (is_array($service)) {
0356                         //convert the array definition to a client object
0357                         $service = new Zend_Service_Solr_Service($service['host'], $service['port'], $service['path']);
0358                         $this->_writeableServices[$id] = $service;
0359                     }
0360 
0361                     $this->_currentWriteService = $id;
0362 
0363                     $backoff *= $this->_backoffEscalation;
0364 
0365                     if ($backoff > $this->_backoffLimit) {
0366                         throw new Zend_Service_Solr_NoServiceAvailableException('No write services were available.  All timeouts exceeded.');
0367                     }
0368                 } while ($this->_writeableServices[$this->_currentWriteService]->ping($backoff) === false);
0369             } else {
0370                 throw new Zend_Service_Solr_NoServiceAvailableException('No write services were available');
0371             }
0372         }
0373 
0374         return $this->_writeableServices[$this->_currentWriteService];
0375     }
0376 
0377     /**
0378      * Set the create documents flag. This determines whether {@link Zend_Service_Solr_Response} objects will
0379      * parse the response and create {@link Zend_Service_Solr_Document} instances in place.
0380      *
0381      * @param boolean $createDocuments
0382      */
0383     public function setCreateDocuments($createDocuments) {
0384         $this->_createDocuments = (bool) $createDocuments;
0385 
0386         // set on current read service
0387         if ($this->_currentReadService) {
0388             $service = $this->_selectReadService();
0389             $service->setCreateDocuments($createDocuments);
0390         }
0391     }
0392 
0393     /**
0394      * Get the current state of teh create documents flag.
0395      *
0396      * @return boolean
0397      */
0398     public function getCreateDocuments() {
0399         return $this->_createDocuments;
0400     }
0401 
0402     /**
0403      * Raw Add Method. Takes a raw post body and sends it to the update service.  Post body
0404      * should be a complete and well formed "add" xml document.
0405      *
0406      * @param string $rawPost
0407      * @return Zend_Service_Solr_Response
0408      *
0409      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0410      */
0411     public function add($rawPost) {
0412         $service = $this->_selectWriteService();
0413 
0414         do {
0415             try {
0416                 return $service->add($rawPost);
0417             } catch (Zend_Service_Solr_HttpTransportException $e) {
0418                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0419                     throw $e;
0420                 }
0421             }
0422 
0423             $service = $this->_selectWriteService(true);
0424         } while ($service);
0425 
0426         return false;
0427     }
0428 
0429     /**
0430      * Add a Solr Document to the index
0431      *
0432      * @param Zend_Service_Solr_Document $document
0433      * @param boolean $allowDups
0434      * @param boolean $overwritePending
0435      * @param boolean $overwriteCommitted
0436      * @return Zend_Service_Solr_Response
0437      *
0438      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0439      */
0440     public function addDocument(Zend_Service_Solr_Document $document, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) {
0441         $service = $this->_selectWriteService();
0442 
0443         do {
0444             try {
0445                 return $service->addDocument($document, $allowDups, $overwritePending, $overwriteCommitted);
0446             } catch (Zend_Service_Solr_HttpTransportException $e) {
0447                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0448                     throw $e;
0449                 }
0450             }
0451 
0452             $service = $this->_selectWriteService(true);
0453         } while ($service);
0454 
0455         return false;
0456     }
0457 
0458     /**
0459      * Add an array of Solr Documents to the index all at once
0460      *
0461      * @param array $documents Should be an array of Zend_Service_Solr_Document instances
0462      * @param boolean $allowDups
0463      * @param boolean $overwritePending
0464      * @param boolean $overwriteCommitted
0465      * @return Zend_Service_Solr_Response
0466      *
0467      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0468      */
0469     public function addDocuments($documents, $allowDups = false, $overwritePending = true, $overwriteCommitted = true) {
0470         $service = $this->_selectWriteService();
0471 
0472         do {
0473             try {
0474                 return $service->addDocuments($documents, $allowDups, $overwritePending, $overwriteCommitted);
0475             } catch (Zend_Service_Solr_HttpTransportException $e) {
0476                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0477                     throw $e;
0478                 }
0479             }
0480 
0481             $service = $this->_selectWriteService(true);
0482         } while ($service);
0483 
0484         return false;
0485     }
0486 
0487     /**
0488      * Send a commit command.  Will be synchronous unless both wait parameters are set
0489      * to false.
0490      *
0491      * @param boolean $waitFlush
0492      * @param boolean $waitSearcher
0493      * @return Zend_Service_Solr_Response
0494      *
0495      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0496      */
0497     public function commit($optimize = true, $waitFlush = true, $waitSearcher = true, $timeout = 3600) {
0498         $service = $this->_selectWriteService();
0499 
0500         do {
0501             try {
0502                 return $service->commit($optimize, $waitFlush, $waitSearcher, $timeout);
0503             } catch (Zend_Service_Solr_HttpTransportException $e) {
0504                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0505                     throw $e;
0506                 }
0507             }
0508 
0509             $service = $this->_selectWriteService(true);
0510         } while ($service);
0511 
0512         return false;
0513     }
0514 
0515     /**
0516      * Raw Delete Method. Takes a raw post body and sends it to the update service. Body should be
0517      * a complete and well formed "delete" xml document
0518      *
0519      * @param string $rawPost
0520      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
0521      * @return Zend_Service_Solr_Response
0522      *
0523      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0524      */
0525     public function delete($rawPost, $timeout = 3600) {
0526         $service = $this->_selectWriteService();
0527 
0528         do {
0529             try {
0530                 return $service->delete($rawPost, $timeout);
0531             } catch (Zend_Service_Solr_HttpTransportException $e) {
0532                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0533                     throw $e;
0534                 }
0535             }
0536 
0537             $service = $this->_selectWriteService(true);
0538         } while ($service);
0539 
0540         return false;
0541     }
0542 
0543     /**
0544      * Create a delete document based on document ID
0545      *
0546      * @param string $id
0547      * @param boolean $fromPending
0548      * @param boolean $fromCommitted
0549      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
0550      * @return Zend_Service_Solr_Response
0551      *
0552      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0553      */
0554     public function deleteById($id, $fromPending = true, $fromCommitted = true, $timeout = 3600) {
0555         $service = $this->_selectWriteService();
0556 
0557         do {
0558             try {
0559                 return $service->deleteById($id, $fromPending, $fromCommitted, $timeout);
0560             } catch (Zend_Service_Solr_HttpTransportException $e) {
0561                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0562                     throw $e;
0563                 }
0564             }
0565 
0566             $service = $this->_selectWriteService(true);
0567         } while ($service);
0568 
0569         return false;
0570     }
0571 
0572     /**
0573      * Create and post a delete document based on multiple document IDs.
0574      *
0575      * @param array $ids Expected to be utf-8 encoded strings
0576      * @param boolean $fromPending
0577      * @param boolean $fromCommitted
0578      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
0579      * @return Zend_Service_Solr_Response
0580      *
0581      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0582      */
0583     public function deleteByMultipleIds($ids, $fromPending = true, $fromCommitted = true, $timeout = 3600) {
0584         $service = $this->_selectWriteService();
0585 
0586         do {
0587             try {
0588                 return $service->deleteByMultipleId($ids, $fromPending, $fromCommitted, $timeout);
0589             } catch (Zend_Service_Solr_HttpTransportException $e) {
0590                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0591                     throw $e;
0592                 }
0593             }
0594 
0595             $service = $this->_selectWriteService(true);
0596         } while ($service);
0597 
0598         return false;
0599     }
0600 
0601     /**
0602      * Create a delete document based on a query and submit it
0603      *
0604      * @param string $rawQuery
0605      * @param boolean $fromPending
0606      * @param boolean $fromCommitted
0607      * @param float $timeout Maximum expected duration of the delete operation on the server (otherwise, will throw a communication exception)
0608      * @return Zend_Service_Solr_Response
0609      *
0610      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0611      */
0612     public function deleteByQuery($rawQuery, $fromPending = true, $fromCommitted = true, $timeout = 3600) {
0613         $service = $this->_selectWriteService();
0614 
0615         do {
0616             try {
0617                 return $service->deleteByQuery($rawQuery, $fromPending, $fromCommitted, $timeout);
0618             } catch (Zend_Service_Solr_HttpTransportException $e) {
0619                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0620                     throw $e;
0621                 }
0622             }
0623 
0624             $service = $this->_selectWriteService(true);
0625         } while ($service);
0626 
0627         return false;
0628     }
0629 
0630     /**
0631      * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
0632      * to use Solr Cell and what parameters are available.
0633      *
0634      * NOTE: when passing an Zend_Service_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
0635      * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
0636      * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also
0637      * pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
0638      *
0639      * @param string $file Path to file to extract data from
0640      * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
0641      * @param Zend_Service_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
0642      * @param string $mimetype optional mimetype specification (for the file being extracted)
0643      *
0644      * @return Zend_Service_Solr_Response
0645      *
0646      * @throws Zend_Service_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
0647      */
0648     public function extract($file, $params = array(), $document = null, $mimetype = 'application/octet-stream') {
0649         $service = $this->_selectWriteService();
0650 
0651         do {
0652             try {
0653                 return $service->extract($file, $params, $document, $mimetype);
0654             } catch (Zend_Service_Solr_HttpTransportException $e) {
0655                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0656                     throw $e;
0657                 }
0658             }
0659 
0660             $service = $this->_selectWriteService(true);
0661         } while ($service);
0662 
0663         return false;
0664     }
0665 
0666     /**
0667      * Use Solr Cell to extract document contents. See {@link http://wiki.apache.org/solr/ExtractingRequestHandler} for information on how
0668      * to use Solr Cell and what parameters are available.
0669      *
0670      * NOTE: when passing an Zend_Service_Solr_Document instance, field names and boosts will automatically be prepended by "literal." and "boost."
0671      * as appropriate. Any keys from the $params array will NOT be treated this way. Any mappings from the document will overwrite key / value
0672      * pairs in the params array if they have the same name (e.g. you pass a "literal.id" key and value in your $params array but you also
0673      * pass in a document isntance with an "id" field" - the document's value(s) will take precedence).
0674      *
0675      * @param string $data Data that will be passed to Solr Cell
0676      * @param array $params optional array of key value pairs that will be sent with the post (see Solr Cell documentation)
0677      * @param Zend_Service_Solr_Document $document optional document that will be used to generate post parameters (literal.* and boost.* params)
0678      * @param string $mimetype optional mimetype specification (for the file being extracted)
0679      *
0680      * @return Zend_Service_Solr_Response
0681      *
0682      * @throws Zend_Service_Solr_InvalidArgumentException if $file, $params, or $document are invalid.
0683      *
0684      * @todo Should be using multipart/form-data to post parameter values, but I could not get my implementation to work. Needs revisisted.
0685      */
0686     public function extractFromString($data, $params = array(), $document = null, $mimetype = 'application/octet-stream') {
0687         $service = $this->_selectWriteService();
0688 
0689         do {
0690             try {
0691                 return $service->extractFromString($data, $params, $document, $mimetype);
0692             } catch (Zend_Service_Solr_HttpTransportException $e) {
0693                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0694                     throw $e;
0695                 }
0696             }
0697 
0698             $service = $this->_selectWriteService(true);
0699         } while ($service);
0700 
0701         return false;
0702     }
0703 
0704     /**
0705      * Send an optimize command.  Will be synchronous unless both wait parameters are set
0706      * to false.
0707      *
0708      * @param boolean $waitFlush
0709      * @param boolean $waitSearcher
0710      * @param float $timeout Maximum expected duration of the optimize operation on the server (otherwise, will throw a communication exception)
0711      * @return Zend_Service_Solr_Response
0712      *
0713      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0714      */
0715     public function optimize($waitFlush = true, $waitSearcher = true, $timeout = 3600) {
0716         $service = $this->_selectWriteService();
0717 
0718         do {
0719             try {
0720                 return $service->optimize($waitFlush, $waitSearcher, $timeout);
0721             } catch (Zend_Service_Solr_HttpTransportException $e) {
0722                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0723                     throw $e;
0724                 }
0725             }
0726 
0727             $service = $this->_selectWriteService(true);
0728         } while ($service);
0729 
0730         return false;
0731     }
0732 
0733     /**
0734      * Simple Search interface
0735      *
0736      * @param string $query The raw query string
0737      * @param int $offset The starting offset for result documents
0738      * @param int $limit The maximum number of result documents to return
0739      * @param array $params key / value pairs for query parameters, use arrays for multivalued parameters
0740      * @param string $method The HTTP method (Zend_Service_Solr_Service::METHOD_GET or Zend_Service_Solr_Service::METHOD::POST)
0741      * @return Zend_Service_Solr_Response
0742      *
0743      * @throws Zend_Service_Solr_HttpTransportException If an error occurs during the service call
0744      */
0745     public function search($query, $offset = 0, $limit = 10, $params = array(), $method = Zend_Service_Solr_Service::METHOD_GET) {
0746         $service = $this->_selectReadService();
0747 
0748         do {
0749             try {
0750                 return $service->search($query, $offset, $limit, $params, $method);
0751             } catch (Zend_Service_Solr_HttpTransportException $e) {
0752                 if ($e->getCode() != 0) { //IF NOT COMMUNICATION ERROR
0753                     throw $e;
0754                 }
0755             }
0756 
0757             $service = $this->_selectReadService(true);
0758         } while ($service);
0759 
0760         return false;
0761     }
0762 
0763 }