updated to 1.2
This commit is contained in:
435
includes/document.inc
Normal file
435
includes/document.inc
Normal file
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (c) 2007-2009, Conduit Internet Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* - Neither the name of Conduit Internet Technologies, Inc. nor the names of
|
||||
* its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @copyright Copyright 2007-2009 Conduit Internet Technologies, Inc. (http://conduit-it.com)
|
||||
* @license New BSD (http://solr-php-client.googlecode.com/svn/trunk/COPYING)
|
||||
* @version $Id: Document.php 15 2009-08-04 17:53:08Z donovan.jimenez $
|
||||
*
|
||||
* @package Apache
|
||||
* @subpackage Solr
|
||||
* @author Donovan Jimenez <djimenez@conduit-it.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Additional code Copyright (c) 2011 by Peter Wolanin, and
|
||||
* additional contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program as the file LICENSE.txt; if not, please see
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds Key / Value pairs that represent a Solr Document along with any
|
||||
* associated boost values. Field values can be accessed by direct dereferencing
|
||||
* such as:
|
||||
*
|
||||
* @code
|
||||
* $document->title = 'Something';
|
||||
* echo $document->title;
|
||||
* @endcode
|
||||
*
|
||||
* Additionally, the field values can be iterated with foreach:
|
||||
*
|
||||
* @code
|
||||
* foreach ($document as $fieldName => $fieldValue) {
|
||||
* // ...
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class SearchApiSolrDocument implements IteratorAggregate {
|
||||
|
||||
/**
|
||||
* Document boost value.
|
||||
*
|
||||
* @var float|false
|
||||
*/
|
||||
protected $documentBoost = FALSE;
|
||||
|
||||
/**
|
||||
* Document field values, indexed by name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fields = array();
|
||||
|
||||
/**
|
||||
* Document field boost values, indexed by name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldBoosts = array();
|
||||
|
||||
/**
|
||||
* Clears all boosts and fields from this document.
|
||||
*/
|
||||
public function clear() {
|
||||
$this->documentBoost = FALSE;
|
||||
|
||||
$this->fields = array();
|
||||
$this->fieldBoosts = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current document boost.
|
||||
*
|
||||
* @return float|false
|
||||
* The current document boost, or FALSE if none is set.
|
||||
*/
|
||||
public function getBoost() {
|
||||
return $this->documentBoost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the document boost factor.
|
||||
*
|
||||
* @param float|false $boost
|
||||
* FALSE for default boost, or a positive number for setting a document
|
||||
* boost.
|
||||
*/
|
||||
public function setBoost($boost) {
|
||||
$boost = (float) $boost;
|
||||
|
||||
if ($boost > 0.0) {
|
||||
$this->documentBoost = $boost;
|
||||
}
|
||||
else {
|
||||
$this->documentBoost = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to a multi-valued field
|
||||
*
|
||||
* NOTE: the solr XML format allows you to specify boosts PER value even
|
||||
* though the underlying Lucene implementation only allows a boost per field.
|
||||
* To remedy this, the final field boost value will be the product of all
|
||||
* specified boosts on field values - this is similar to SolrJ's
|
||||
* functionality.
|
||||
*
|
||||
* @code
|
||||
* $doc = new ApacheSolrDocument();
|
||||
* $doc->addField('foo', 'bar', 2.0);
|
||||
* $doc->addField('foo', 'baz', 3.0);
|
||||
* // Resultant field boost will be 6!
|
||||
* echo $doc->getFieldBoost('foo');
|
||||
* @endcode
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
* @param $value
|
||||
* The value to add for the field.
|
||||
* @param float|false $boost
|
||||
* FALSE for default boost, or a positive number for setting a field boost.
|
||||
*/
|
||||
public function addField($key, $value, $boost = FALSE) {
|
||||
if (!isset($this->fields[$key])) {
|
||||
// create holding array if this is the first value
|
||||
$this->fields[$key] = array();
|
||||
}
|
||||
else if (!is_array($this->fields[$key])) {
|
||||
// move existing value into array if it is not already an array
|
||||
$this->fields[$key] = array($this->fields[$key]);
|
||||
}
|
||||
|
||||
if ($this->getFieldBoost($key) === FALSE) {
|
||||
// boost not already set, set it now
|
||||
$this->setFieldBoost($key, $boost);
|
||||
}
|
||||
else if ((float) $boost > 0.0) {
|
||||
// multiply passed boost with current field boost - similar to SolrJ implementation
|
||||
$this->fieldBoosts[$key] *= (float) $boost;
|
||||
}
|
||||
|
||||
// add value to array
|
||||
$this->fields[$key][] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information about a field stored in Solr.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
*
|
||||
* @return array|false
|
||||
* An associative array of info if the field exists, FALSE otherwise.
|
||||
*/
|
||||
public function getField($key) {
|
||||
if (isset($this->fields[$key])) {
|
||||
return array(
|
||||
'name' => $key,
|
||||
'value' => $this->fields[$key],
|
||||
'boost' => $this->getFieldBoost($key)
|
||||
);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a field value.
|
||||
*
|
||||
* Multi-valued fields should be set as arrays or via the addField()
|
||||
* function which will automatically make sure the field is an array.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
* @param string|array $value
|
||||
* The value to set for the field.
|
||||
* @param float|false $boost
|
||||
* FALSE for default boost, or a positive number for setting a field boost.
|
||||
*/
|
||||
public function setField($key, $value, $boost = FALSE) {
|
||||
$this->fields[$key] = $value;
|
||||
$this->setFieldBoost($key, $boost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently set field boost for a document field.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
*
|
||||
* @return float|false
|
||||
* The currently set field boost, or FALSE if none was set.
|
||||
*/
|
||||
public function getFieldBoost($key) {
|
||||
return isset($this->fieldBoosts[$key]) ? $this->fieldBoosts[$key] : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field boost for a document field.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
* @param float|false $boost
|
||||
* FALSE for default boost, or a positive number for setting a field boost.
|
||||
*/
|
||||
public function setFieldBoost($key, $boost) {
|
||||
$boost = (float) $boost;
|
||||
|
||||
if ($boost > 0.0) {
|
||||
$this->fieldBoosts[$key] = $boost;
|
||||
}
|
||||
else {
|
||||
$this->fieldBoosts[$key] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all current field boosts, indexed by field name.
|
||||
*
|
||||
* @return array
|
||||
* An associative array in the format $field_name => $field_boost.
|
||||
*/
|
||||
public function getFieldBoosts() {
|
||||
return $this->fieldBoosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all fields in this document.
|
||||
*
|
||||
* @return array
|
||||
* The names of all fields in this document.
|
||||
*/
|
||||
public function getFieldNames() {
|
||||
return array_keys($this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the values of all fields in this document.
|
||||
*
|
||||
* @return array
|
||||
* The values of all fields in this document.
|
||||
*/
|
||||
public function getFieldValues() {
|
||||
return array_values($this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements IteratorAggregate::getIterator().
|
||||
*
|
||||
* Implementing the IteratorAggregate interface allows the following usage:
|
||||
* @code
|
||||
* foreach ($document as $key => $value) {
|
||||
* // ...
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @return Traversable
|
||||
* An iterator over this document's fields.
|
||||
*/
|
||||
public function getIterator() {
|
||||
$arrayObject = new ArrayObject($this->fields);
|
||||
|
||||
return $arrayObject->getIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter for field values.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
*
|
||||
* @return string|array|null
|
||||
* The value that was set for the field.
|
||||
*/
|
||||
public function __get($key) {
|
||||
return $this->fields[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic setter for field values.
|
||||
*
|
||||
* Multi-valued fields should be set as arrays or via the addField() function
|
||||
* which will automatically make sure the field is an array.
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
* @param string|array $value
|
||||
* The value to set for the field.
|
||||
*/
|
||||
public function __set($key, $value) {
|
||||
$this->setField($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset for fields values.
|
||||
*
|
||||
* Do not call directly. Allows the following usage:
|
||||
* @code
|
||||
* isset($document->some_field);
|
||||
* @endcode
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
*
|
||||
* @return bool
|
||||
* Whether the given key is set in this document.
|
||||
*/
|
||||
public function __isset($key) {
|
||||
return isset($this->fields[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic unset for field values.
|
||||
*
|
||||
* Do not call directly. Allows the following usage:
|
||||
* @code
|
||||
* unset($document->some_field);
|
||||
* @endcode
|
||||
*
|
||||
* @param string $key
|
||||
* The name of the field.
|
||||
*/
|
||||
public function __unset($key) {
|
||||
unset($this->fields[$key]);
|
||||
unset($this->fieldBoosts[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an XML fragment from this document.
|
||||
*
|
||||
* This string can then be used inside a Solr add call.
|
||||
*
|
||||
* @return string
|
||||
* An XML formatted string for this document.
|
||||
*/
|
||||
public function toXml() {
|
||||
$xml = '<doc';
|
||||
|
||||
if ($this->documentBoost !== FALSE) {
|
||||
$xml .= ' boost="' . $this->documentBoost . '"';
|
||||
}
|
||||
|
||||
$xml .= '>';
|
||||
|
||||
foreach ($this->fields as $key => $value) {
|
||||
$fieldBoost = $this->getFieldBoost($key);
|
||||
$key = htmlspecialchars($key, ENT_COMPAT, 'UTF-8');
|
||||
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $multivalue) {
|
||||
$xml .= '<field name="' . $key . '"';
|
||||
|
||||
if ($fieldBoost !== FALSE) {
|
||||
$xml .= ' boost="' . $fieldBoost . '"';
|
||||
|
||||
// Only set the boost for the first field in the set.
|
||||
$fieldBoost = FALSE;
|
||||
}
|
||||
|
||||
$xml .= '>' . htmlspecialchars($multivalue, ENT_NOQUOTES, 'UTF-8') . '</field>';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$xml .= '<field name="' . $key . '"';
|
||||
|
||||
if ($fieldBoost !== FALSE) {
|
||||
$xml .= ' boost="' . $fieldBoost . '"';
|
||||
}
|
||||
|
||||
$xml .= '>' . htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8') . '</field>';
|
||||
}
|
||||
}
|
||||
|
||||
$xml .= '</doc>';
|
||||
|
||||
// Remove any control characters to avoid Solr XML parser exception.
|
||||
return self::stripCtrlChars($xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes XML for sending to Solr.
|
||||
*
|
||||
* Replaces control (non-printable) characters that are invalid to Solr's XML
|
||||
* parser with a space.
|
||||
*
|
||||
* @param string $string
|
||||
* The string to sanitize.
|
||||
*
|
||||
* @return string
|
||||
* A string safe for including in a Solr request.
|
||||
*/
|
||||
public static function stripCtrlChars($string) {
|
||||
// See: http://w3.org/International/questions/qa-forms-utf-8.html
|
||||
// Printable utf-8 does not include any of these chars below x7F
|
||||
return preg_replace('@[\x00-\x08\x0B\x0C\x0E-\x1F]@', ' ', $string);
|
||||
}
|
||||
}
|
2057
includes/service.inc
Normal file
2057
includes/service.inc
Normal file
File diff suppressed because it is too large
Load Diff
901
includes/solr_connection.inc
Normal file
901
includes/solr_connection.inc
Normal file
@@ -0,0 +1,901 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (c) 2007-2009, Conduit Internet Technologies, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* - Neither the name of Conduit Internet Technologies, Inc. nor the names of
|
||||
* its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @copyright Copyright 2007-2009 Conduit Internet Technologies, Inc. (http://conduit-it.com)
|
||||
* @license New BSD (http://solr-php-client.googlecode.com/svn/trunk/COPYING)
|
||||
* @version $Id: Service.php 22 2009-11-09 22:46:54Z donovan.jimenez $
|
||||
*
|
||||
* @package Apache
|
||||
* @subpackage Solr
|
||||
* @author Donovan Jimenez <djimenez@conduit-it.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Additional code Copyright (c) 2008-2011 by Robert Douglass, James McKinney,
|
||||
* Jacob Singh, Alejandro Garza, Peter Wolanin, and additional contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program as the file LICENSE.txt; if not, please see
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Starting point for the Solr API. Represents a Solr server resource and has
|
||||
* methods for pinging, adding, deleting, committing, optimizing and searching.
|
||||
*/
|
||||
|
||||
class SearchApiSolrConnection implements SearchApiSolrConnectionInterface {
|
||||
|
||||
/**
|
||||
* Defines how NamedLists should be formatted in the output.
|
||||
*
|
||||
* This specifically affects facet counts. Valid values are 'map' (default) or
|
||||
* 'flat'.
|
||||
*/
|
||||
const NAMED_LIST_FORMAT = 'map';
|
||||
|
||||
/**
|
||||
* Path to the ping servlet.
|
||||
*/
|
||||
const PING_SERVLET = 'admin/ping';
|
||||
|
||||
/**
|
||||
* Path to the update servlet.
|
||||
*/
|
||||
const UPDATE_SERVLET = 'update';
|
||||
|
||||
/**
|
||||
* Path to the search servlet.
|
||||
*/
|
||||
const SEARCH_SERVLET = 'select';
|
||||
|
||||
/**
|
||||
* Path to the luke servlet.
|
||||
*/
|
||||
const LUKE_SERVLET = 'admin/luke';
|
||||
|
||||
/**
|
||||
* Path to the system servlet.
|
||||
*/
|
||||
const SYSTEM_SERVLET = 'admin/system';
|
||||
|
||||
/**
|
||||
* Path to the stats servlet.
|
||||
*/
|
||||
const STATS_SERVLET = 'admin/stats.jsp';
|
||||
|
||||
/**
|
||||
* Path to the stats servlet for Solr 4.x servers.
|
||||
*/
|
||||
const STATS_SERVLET_4 = 'admin/mbeans?wt=xml&stats=true';
|
||||
|
||||
/**
|
||||
* Path to the file servlet.
|
||||
*/
|
||||
const FILE_SERVLET = 'admin/file';
|
||||
|
||||
/**
|
||||
* The options passed when creating this connection.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* The Solr server's URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $base_url;
|
||||
|
||||
/**
|
||||
* Cached URL to the update servlet.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $update_url;
|
||||
|
||||
/**
|
||||
* The HTTP method to use for search requests.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $method;
|
||||
|
||||
/**
|
||||
* HTTP Basic Authentication header to set for requests to the Solr server.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $http_auth;
|
||||
|
||||
/**
|
||||
* The stream context to use for requests to the Solr server.
|
||||
*
|
||||
* Defaults to NULL (= pass no context at all).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $stream_context;
|
||||
|
||||
/**
|
||||
* Cache for the metadata from admin/luke.
|
||||
*
|
||||
* Contains an array of response objects, keyed by the number of "top terms".
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see getLuke()
|
||||
*/
|
||||
protected $luke = array();
|
||||
|
||||
/**
|
||||
* Cache for information about the Solr core.
|
||||
*
|
||||
* @var SimpleXMLElement
|
||||
*
|
||||
* @see getStats()
|
||||
*/
|
||||
protected $stats;
|
||||
|
||||
/**
|
||||
* Cache for system information.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @see getSystemInfo()
|
||||
*/
|
||||
protected $system_info;
|
||||
|
||||
/**
|
||||
* Flag that denotes whether to use soft commits for Solr 4.x.
|
||||
*
|
||||
* Defaults to FALSE.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $soft_commit = FALSE;
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::__construct().
|
||||
*
|
||||
* Valid options include:
|
||||
* - scheme: Scheme of the base URL of the Solr server. Most probably "http"
|
||||
* or "https". Defaults to "http".
|
||||
* - host: The host name (or IP) of the Solr server. Defaults to
|
||||
* "localhost".
|
||||
* - port: The port of the Solr server. Defaults to 8983.
|
||||
* - path: The base path to the Solr server. Defaults to "/solr/".
|
||||
* - http_user: If both this and "http_pass" are set, will use this
|
||||
* information to add basic HTTP authentication to all requests to the
|
||||
* Solr server. Not set by default.
|
||||
* - http_pass: See "http_user".
|
||||
* - http_method: The HTTP method to use for searches. Can be either "GET"
|
||||
* or "POST". Defaults to "POST".
|
||||
*/
|
||||
public function __construct(array $options) {
|
||||
$options += array(
|
||||
'scheme' => 'http',
|
||||
'host' => 'localhost',
|
||||
'port' => 8983,
|
||||
'path' => 'solr',
|
||||
'http_user' => NULL,
|
||||
'http_pass' => NULL,
|
||||
'http_method' => 'POST',
|
||||
);
|
||||
$this->options = $options;
|
||||
|
||||
$path = '/' . trim($options['path'], '/') . '/';
|
||||
$this->base_url = $options['scheme'] . '://' . $options['host'] . ':' . $options['port'] . $path;
|
||||
|
||||
// Make sure we always have a valid method set, default to POST.
|
||||
$this->method = $options['http_method'] == 'GET' ? 'GET' : 'POST';
|
||||
|
||||
// Set HTTP Basic Authentication parameter, if login data was set.
|
||||
if (strlen($options['http_user']) && strlen($options['http_pass'])) {
|
||||
$this->http_auth = 'Basic ' . base64_encode($options['http_user'] . ':' . $options['http_pass']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::ping().
|
||||
*/
|
||||
public function ping($timeout = 2) {
|
||||
$start = microtime(TRUE);
|
||||
|
||||
if ($timeout <= 0.0) {
|
||||
$timeout = -1;
|
||||
}
|
||||
$pingUrl = $this->constructUrl(self::PING_SERVLET);
|
||||
|
||||
// Attempt a HEAD request to the Solr ping url.
|
||||
$options = array(
|
||||
'method' => 'HEAD',
|
||||
'timeout' => $timeout,
|
||||
);
|
||||
$response = $this->makeHttpRequest($pingUrl, $options);
|
||||
|
||||
if ($response->code == 200) {
|
||||
// Add 1 µs to the ping time so we never return 0.
|
||||
return (microtime(TRUE) - $start) + 1E-6;
|
||||
}
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::setSoftCommit().
|
||||
*/
|
||||
public function setSoftCommit($soft_commit) {
|
||||
$this->soft_commit = (bool) $soft_commit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getSoftCommit().
|
||||
*/
|
||||
public function getSoftCommit() {
|
||||
return $this->soft_commit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::setStreamContext().
|
||||
*/
|
||||
public function setStreamContext($stream_context) {
|
||||
$this->stream_context = $stream_context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getStreamContext().
|
||||
*/
|
||||
public function getStreamContext() {
|
||||
return $this->stream_context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the cache ID to use for this connection.
|
||||
*
|
||||
* @param $suffix
|
||||
* (optional) A suffix to append to the string to make it unique.
|
||||
*
|
||||
* @return string|null
|
||||
* The cache ID to use for this connection and usage; or NULL if no caching
|
||||
* should take place.
|
||||
*/
|
||||
protected function getCacheId($suffix = '') {
|
||||
if (!empty($this->options['server'])) {
|
||||
$cid = $this->options['server'];
|
||||
return $suffix ? "$cid:$suffix" : $cid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the /admin/system servlet to retrieve system information.
|
||||
*
|
||||
* Stores the retrieved information in $system_info.
|
||||
*
|
||||
* @see getSystemInfo()
|
||||
*/
|
||||
protected function setSystemInfo() {
|
||||
$cid = $this->getCacheId(__FUNCTION__);
|
||||
if ($cid) {
|
||||
$cache = cache_get($cid, 'cache_search_api_solr');
|
||||
if ($cache) {
|
||||
$this->system_info = json_decode($cache->data);
|
||||
}
|
||||
}
|
||||
// Second pass to populate the cache if necessary.
|
||||
if (empty($this->system_info)) {
|
||||
$url = $this->constructUrl(self::SYSTEM_SERVLET, array('wt' => 'json'));
|
||||
$response = $this->sendRawGet($url);
|
||||
$this->system_info = json_decode($response->data);
|
||||
if ($cid) {
|
||||
cache_set($cid, $response->data, 'cache_search_api_solr');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getSystemInfo().
|
||||
*/
|
||||
public function getSystemInfo() {
|
||||
if (!isset($this->system_info)) {
|
||||
$this->setSystemInfo();
|
||||
}
|
||||
return $this->system_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets $this->luke with the metadata about the index from admin/luke.
|
||||
*/
|
||||
protected function setLuke($num_terms = 0) {
|
||||
if (empty($this->luke[$num_terms])) {
|
||||
$cid = $this->getCacheId(__FUNCTION__ . ":$num_terms");
|
||||
if ($cid) {
|
||||
$cache = cache_get($cid, 'cache_search_api_solr');
|
||||
if (isset($cache->data)) {
|
||||
$this->luke = $cache->data;
|
||||
}
|
||||
}
|
||||
// Second pass to populate the cache if necessary.
|
||||
if (empty($this->luke[$num_terms])) {
|
||||
$params = array(
|
||||
'numTerms' => "$num_terms",
|
||||
'wt' => 'json',
|
||||
'json.nl' => self::NAMED_LIST_FORMAT,
|
||||
);
|
||||
$url = $this->constructUrl(self::LUKE_SERVLET, $params);
|
||||
$this->luke[$num_terms] = $this->sendRawGet($url);
|
||||
if ($cid) {
|
||||
cache_set($cid, $this->luke, 'cache_search_api_solr');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getFields().
|
||||
*/
|
||||
public function getFields($num_terms = 0) {
|
||||
$fields = array();
|
||||
foreach ($this->getLuke($num_terms)->fields as $name => $info) {
|
||||
$fields[$name] = new SearchApiSolrField($info);
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getLuke().
|
||||
*/
|
||||
public function getLuke($num_terms = 0) {
|
||||
if (!isset($this->luke[$num_terms])) {
|
||||
$this->setLuke($num_terms);
|
||||
}
|
||||
return $this->luke[$num_terms];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getSolrVersion().
|
||||
*/
|
||||
public function getSolrVersion() {
|
||||
$system_info = $this->getSystemInfo();
|
||||
// Get our solr version number
|
||||
if (isset($system_info->lucene->{'solr-spec-version'})) {
|
||||
return $system_info->lucene->{'solr-spec-version'}[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores information about the Solr core in $this->stats.
|
||||
*/
|
||||
protected function setStats() {
|
||||
$data = $this->getLuke();
|
||||
$solr_version = $this->getSolrVersion();
|
||||
// Only try to get stats if we have connected to the index.
|
||||
if (empty($this->stats) && isset($data->index->numDocs)) {
|
||||
$cid = $this->getCacheId(__FUNCTION__);
|
||||
if ($cid) {
|
||||
$cache = cache_get($cid, 'cache_search_api_solr');
|
||||
if (isset($cache->data)) {
|
||||
$this->stats = simplexml_load_string($cache->data);
|
||||
}
|
||||
}
|
||||
// Second pass to populate the cache if necessary.
|
||||
if (empty($this->stats)) {
|
||||
if ($solr_version >= 4) {
|
||||
$url = $this->constructUrl(self::STATS_SERVLET_4);
|
||||
}
|
||||
else {
|
||||
$url = $this->constructUrl(self::STATS_SERVLET);
|
||||
}
|
||||
$response = $this->sendRawGet($url);
|
||||
$this->stats = simplexml_load_string($response->data);
|
||||
if ($this->env_id) {
|
||||
cache_set($cid, $response->data, 'cache_search_api_solr');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getStats().
|
||||
*/
|
||||
public function getStats() {
|
||||
if (!isset($this->stats)) {
|
||||
$this->setStats();
|
||||
}
|
||||
return $this->stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getStatsSummary().
|
||||
*/
|
||||
public function getStatsSummary() {
|
||||
$stats = $this->getStats();
|
||||
$solr_version = $this->getSolrVersion();
|
||||
|
||||
$summary = array(
|
||||
'@pending_docs' => '',
|
||||
'@autocommit_time_seconds' => '',
|
||||
'@autocommit_time' => '',
|
||||
'@deletes_by_id' => '',
|
||||
'@deletes_by_query' => '',
|
||||
'@deletes_total' => '',
|
||||
'@schema_version' => '',
|
||||
'@core_name' => '',
|
||||
'@index_size' => '',
|
||||
);
|
||||
|
||||
if (!empty($stats)) {
|
||||
if ($solr_version <= 3) {
|
||||
$docs_pending_xpath = $stats->xpath('//stat[@name="docsPending"]');
|
||||
$summary['@pending_docs'] = (int) trim(current($docs_pending_xpath));
|
||||
$max_time_xpath = $stats->xpath('//stat[@name="autocommit maxTime"]');
|
||||
$max_time = (int) trim(current($max_time_xpath));
|
||||
// Convert to seconds.
|
||||
$summary['@autocommit_time_seconds'] = $max_time / 1000;
|
||||
$summary['@autocommit_time'] = format_interval($max_time / 1000);
|
||||
$deletes_id_xpath = $stats->xpath('//stat[@name="deletesById"]');
|
||||
$summary['@deletes_by_id'] = (int) trim(current($deletes_id_xpath));
|
||||
$deletes_query_xpath = $stats->xpath('//stat[@name="deletesByQuery"]');
|
||||
$summary['@deletes_by_query'] = (int) trim(current($deletes_query_xpath));
|
||||
$summary['@deletes_total'] = $summary['@deletes_by_id'] + $summary['@deletes_by_query'];
|
||||
$schema = $stats->xpath('/solr/schema[1]');
|
||||
$summary['@schema_version'] = trim($schema[0]);
|
||||
$core = $stats->xpath('/solr/core[1]');
|
||||
$summary['@core_name'] = trim($core[0]);
|
||||
$size_xpath = $stats->xpath('//stat[@name="indexSize"]');
|
||||
$summary['@index_size'] = trim(current($size_xpath));
|
||||
}
|
||||
else {
|
||||
$system_info = $this->getSystemInfo();
|
||||
$docs_pending_xpath = $stats->xpath('//lst["stats"]/long[@name="docsPending"]');
|
||||
$summary['@pending_docs'] = (int) trim(current($docs_pending_xpath));
|
||||
$max_time_xpath = $stats->xpath('//lst["stats"]/str[@name="autocommit maxTime"]');
|
||||
$max_time = (int) trim(current($max_time_xpath));
|
||||
// Convert to seconds.
|
||||
$summary['@autocommit_time_seconds'] = $max_time / 1000;
|
||||
$summary['@autocommit_time'] = format_interval($max_time / 1000);
|
||||
$deletes_id_xpath = $stats->xpath('//lst["stats"]/long[@name="deletesById"]');
|
||||
$summary['@deletes_by_id'] = (int) trim(current($deletes_id_xpath));
|
||||
$deletes_query_xpath = $stats->xpath('//lst["stats"]/long[@name="deletesByQuery"]');
|
||||
$summary['@deletes_by_query'] = (int) trim(current($deletes_query_xpath));
|
||||
$summary['@deletes_total'] = $summary['@deletes_by_id'] + $summary['@deletes_by_query'];
|
||||
$schema = $system_info->core->schema;
|
||||
$summary['@schema_version'] = $schema;
|
||||
$core = $stats->xpath('//lst["core"]/str[@name="coreName"]');
|
||||
$summary['@core_name'] = trim(current($core));
|
||||
$size_xpath = $stats->xpath('//lst["core"]/str[@name="indexSize"]');
|
||||
$summary['@index_size'] = trim(current($size_xpath));
|
||||
}
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::clearCache().
|
||||
*/
|
||||
public function clearCache() {
|
||||
if ($cid = $this->getCacheId()) {
|
||||
cache_clear_all($cid, 'cache_search_api_solr', TRUE);
|
||||
cache_clear_all($cid, 'cache_search_api_solr', TRUE);
|
||||
}
|
||||
$this->luke = array();
|
||||
$this->stats = NULL;
|
||||
$this->system_info = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the reponse code and throws an exception if it's not 200.
|
||||
*
|
||||
* @param object $response
|
||||
* A response object.
|
||||
*
|
||||
* @return object
|
||||
* The passed response object.
|
||||
*
|
||||
* @throws SearchApiException
|
||||
* If the object's HTTP status is not 200.
|
||||
*/
|
||||
protected function checkResponse($response) {
|
||||
$code = (int) $response->code;
|
||||
|
||||
if ($code != 200) {
|
||||
if ($code >= 400 && $code != 403 && $code != 404) {
|
||||
// Add details, like Solr's exception message.
|
||||
$response->status_message .= $response->data;
|
||||
}
|
||||
throw new SearchApiException('"' . $code . '" Status: ' . $response->status_message);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::makeServletRequest().
|
||||
*/
|
||||
public function makeServletRequest($servlet, array $params = array(), array $options = array()) {
|
||||
// Add default params.
|
||||
$params += array(
|
||||
'wt' => 'json',
|
||||
'json.nl' => self::NAMED_LIST_FORMAT,
|
||||
);
|
||||
|
||||
$url = $this->constructUrl($servlet, $params);
|
||||
$response = $this->makeHttpRequest($url, $options);
|
||||
|
||||
return $this->checkResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Central method for making a GET operation against this Solr Server
|
||||
*/
|
||||
protected function sendRawGet($url, array $options = array()) {
|
||||
$options['method'] = 'GET';
|
||||
$response = $this->makeHttpRequest($url, $options);
|
||||
|
||||
return $this->checkResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Central method for making a POST operation against this Solr Server
|
||||
*/
|
||||
protected function sendRawPost($url, array $options = array()) {
|
||||
$options['method'] = 'POST';
|
||||
// Normally we use POST to send XML documents.
|
||||
if (empty($options['headers']['Content-Type'])) {
|
||||
$options['headers']['Content-Type'] = 'text/xml; charset=UTF-8';
|
||||
}
|
||||
$response = $this->makeHttpRequest($url, $options);
|
||||
|
||||
return $this->checkResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an HTTP request to Solr.
|
||||
*
|
||||
* This is just a wrapper around drupal_http_request().
|
||||
*/
|
||||
protected function makeHttpRequest($url, array $options = array()) {
|
||||
if (empty($options['method']) || $options['method'] == 'GET' || $options['method'] == 'HEAD') {
|
||||
// Make sure we are not sending a request body.
|
||||
$options['data'] = NULL;
|
||||
}
|
||||
if ($this->http_auth) {
|
||||
$options['headers']['Authorization'] = $this->http_auth;
|
||||
}
|
||||
if ($this->stream_context) {
|
||||
$options['context'] = $this->stream_context;
|
||||
}
|
||||
|
||||
$result = drupal_http_request($url, $options);
|
||||
|
||||
if (!isset($result->code) || $result->code < 0) {
|
||||
$result->code = 0;
|
||||
$result->status_message = 'Request failed';
|
||||
$result->protocol = 'HTTP/1.0';
|
||||
}
|
||||
// Additional information may be in the error property.
|
||||
if (isset($result->error)) {
|
||||
$result->status_message .= ': ' . check_plain($result->error);
|
||||
}
|
||||
|
||||
if (!isset($result->data)) {
|
||||
$result->data = '';
|
||||
$result->response = NULL;
|
||||
}
|
||||
else {
|
||||
$response = json_decode($result->data);
|
||||
if (is_object($response)) {
|
||||
foreach ($response as $key => $value) {
|
||||
$result->$key = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::escape().
|
||||
*/
|
||||
public static function escape($value, $version = 0) {
|
||||
$replacements = array();
|
||||
|
||||
$specials = array('+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', "\\");
|
||||
// Solr 4.x introduces regular expressions, making the slash also a special
|
||||
// character.
|
||||
if ($version >= 4) {
|
||||
$specials[] = '/';
|
||||
}
|
||||
|
||||
foreach ($specials as $special) {
|
||||
$replacements[$special] = "\\$special";
|
||||
}
|
||||
|
||||
return strtr($value, $replacements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::escapePhrase().
|
||||
*/
|
||||
public static function escapePhrase($value) {
|
||||
$replacements['"'] = '\"';
|
||||
$replacements["\\"] = "\\\\";
|
||||
return strtr($value, $replacements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::phrase().
|
||||
*/
|
||||
public static function phrase($value) {
|
||||
return '"' . self::escapePhrase($value) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::escapeFieldName().
|
||||
*/
|
||||
public static function escapeFieldName($value) {
|
||||
$value = str_replace(':', '\:', $value);
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP URL for a certain servlet on the Solr server.
|
||||
*
|
||||
* @param $servlet
|
||||
* A string path to a Solr request handler.
|
||||
* @param array $params
|
||||
* Additional GET parameters to append to the URL.
|
||||
* @param $added_query_string
|
||||
* Additional query string to append to the URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function constructUrl($servlet, array $params = array(), $added_query_string = NULL) {
|
||||
// PHP's built in http_build_query() doesn't give us the format Solr wants.
|
||||
$query_string = $this->httpBuildQuery($params);
|
||||
|
||||
if ($query_string) {
|
||||
$query_string = '?' . $query_string;
|
||||
if ($added_query_string) {
|
||||
$query_string = $query_string . '&' . $added_query_string;
|
||||
}
|
||||
}
|
||||
elseif ($added_query_string) {
|
||||
$query_string = '?' . $added_query_string;
|
||||
}
|
||||
|
||||
return $this->base_url . $servlet . $query_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::getBaseUrl().
|
||||
*/
|
||||
public function getBaseUrl() {
|
||||
return $this->base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::setBaseUrl().
|
||||
*/
|
||||
public function setBaseUrl($url) {
|
||||
$this->base_url = $url;
|
||||
$this->update_url = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::update().
|
||||
*/
|
||||
public function update($rawPost, $timeout = FALSE) {
|
||||
if (empty($this->update_url)) {
|
||||
// Store the URL in an instance variable since many updates may be sent
|
||||
// via a single instance of this class.
|
||||
$this->update_url = $this->constructUrl(self::UPDATE_SERVLET, array('wt' => 'json'));
|
||||
}
|
||||
$options['data'] = $rawPost;
|
||||
if ($timeout) {
|
||||
$options['timeout'] = $timeout;
|
||||
}
|
||||
return $this->sendRawPost($this->update_url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::addDocuments().
|
||||
*/
|
||||
public function addDocuments(array $documents, $overwrite = NULL, $commitWithin = NULL) {
|
||||
$attr = '';
|
||||
|
||||
if (isset($overwrite)) {
|
||||
$attr .= ' overwrite="' . ($overwrite ? 'true"' : 'false"');
|
||||
}
|
||||
if (isset($commitWithin)) {
|
||||
$attr .= ' commitWithin="' . ((int) $commitWithin) . '"';
|
||||
}
|
||||
|
||||
$rawPost = "<add$attr>";
|
||||
foreach ($documents as $document) {
|
||||
if (is_object($document) && ($document instanceof SearchApiSolrDocument)) {
|
||||
$rawPost .= $document->toXml();
|
||||
}
|
||||
}
|
||||
$rawPost .= '</add>';
|
||||
|
||||
return $this->update($rawPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::commit().
|
||||
*/
|
||||
public function commit($waitSearcher = TRUE, $timeout = 3600) {
|
||||
return $this->optimizeOrCommit('commit', $waitSearcher, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::deleteById().
|
||||
*/
|
||||
public function deleteById($id, $timeout = 3600) {
|
||||
return $this->deleteByMultipleIds(array($id), $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::deleteByMultipleIds().
|
||||
*/
|
||||
public function deleteByMultipleIds(array $ids, $timeout = 3600) {
|
||||
$rawPost = '<delete>';
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$rawPost .= '<id>' . htmlspecialchars($id, ENT_NOQUOTES, 'UTF-8') . '</id>';
|
||||
}
|
||||
$rawPost .= '</delete>';
|
||||
|
||||
return $this->update($rawPost, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::deleteByQuery().
|
||||
*/
|
||||
public function deleteByQuery($rawQuery, $timeout = 3600) {
|
||||
$rawPost = '<delete><query>' . htmlspecialchars($rawQuery, ENT_NOQUOTES, 'UTF-8') . '</query></delete>';
|
||||
|
||||
return $this->update($rawPost, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::optimize().
|
||||
*/
|
||||
public function optimize($waitSearcher = TRUE, $timeout = 3600) {
|
||||
return $this->optimizeOrCommit('optimize', $waitSearcher, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an commit or optimize command to the Solr server.
|
||||
*
|
||||
* Will be synchronous unless $waitSearcher is set to FALSE.
|
||||
*
|
||||
* @param $type
|
||||
* Either "commit" or "optimize".
|
||||
* @param $waitSearcher
|
||||
* (optional) Wait until a new searcher is opened and registered as the main
|
||||
* query searcher, making the changes visible. Defaults to true.
|
||||
* @param $timeout
|
||||
* Seconds to wait until timing out with an exception. Defaults to an hour.
|
||||
*
|
||||
* @return
|
||||
* A response object.
|
||||
*
|
||||
* @throws SearchApiException
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
protected function optimizeOrCommit($type, $waitSearcher = TRUE, $timeout = 3600) {
|
||||
$waitSearcher = $waitSearcher ? '' : ' waitSearcher="false"';
|
||||
|
||||
if ($this->getSolrVersion() <= 3) {
|
||||
$rawPost = "<$type$waitSearcher />";
|
||||
}
|
||||
else {
|
||||
$softCommit = ($this->soft_commit) ? ' softCommit="true"' : '';
|
||||
$rawPost = "<$type$waitSearcher$softCommit />";
|
||||
}
|
||||
|
||||
$response = $this->update($rawPost, $timeout);
|
||||
$this->clearCache();
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like PHP's built in http_build_query(), but uses rawurlencode() and no [] for repeated params.
|
||||
*/
|
||||
protected function httpBuildQuery(array $query, $parent = '') {
|
||||
$params = array();
|
||||
|
||||
foreach ($query as $key => $value) {
|
||||
$key = ($parent ? $parent : rawurlencode($key));
|
||||
|
||||
// Recurse into children.
|
||||
if (is_array($value)) {
|
||||
$params[] = $this->httpBuildQuery($value, $key);
|
||||
}
|
||||
// If a query parameter value is NULL, only append its key.
|
||||
elseif (!isset($value)) {
|
||||
$params[] = $key;
|
||||
}
|
||||
else {
|
||||
$params[] = $key . '=' . rawurlencode($value);
|
||||
}
|
||||
}
|
||||
|
||||
return implode('&', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements SearchApiSolrConnectionInterface::search().
|
||||
*/
|
||||
public function search($query = NULL, array $params = array(), $method = 'GET') {
|
||||
// Always use JSON. See
|
||||
// http://code.google.com/p/solr-php-client/issues/detail?id=6#c1 for
|
||||
// reasoning.
|
||||
$params['wt'] = 'json';
|
||||
// Additional default params.
|
||||
$params += array(
|
||||
'json.nl' => self::NAMED_LIST_FORMAT,
|
||||
);
|
||||
if ($query) {
|
||||
$params['q'] = $query;
|
||||
}
|
||||
// PHP's built-in http_build_query() doesn't give us the format Solr wants.
|
||||
$queryString = $this->httpBuildQuery($params);
|
||||
|
||||
if ($this->method == 'GET') {
|
||||
$searchUrl = $this->constructUrl(self::SEARCH_SERVLET, array(), $queryString);
|
||||
return $this->sendRawGet($searchUrl);
|
||||
}
|
||||
else if ($this->method == 'POST') {
|
||||
$searchUrl = $this->constructUrl(self::SEARCH_SERVLET);
|
||||
$options['data'] = $queryString;
|
||||
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||
return $this->sendRawPost($searchUrl, $options);
|
||||
}
|
||||
}
|
||||
}
|
365
includes/solr_connection.interface.inc
Normal file
365
includes/solr_connection.interface.inc
Normal file
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* The interface for a Solr connection class.
|
||||
*/
|
||||
interface SearchApiSolrConnectionInterface {
|
||||
|
||||
/**
|
||||
* Constructs a Solr connection objects.
|
||||
*
|
||||
* @param array $options
|
||||
* An array containing construction arguments.
|
||||
*/
|
||||
public function __construct(array $options);
|
||||
|
||||
/**
|
||||
* Calls the /admin/ping servlet, to test the connection to the server.
|
||||
*
|
||||
* @param int|false $timeout
|
||||
* Maximum time to wait for ping in seconds, -1 for unlimited (default 2).
|
||||
*
|
||||
* @return float|false
|
||||
* Seconds taken to ping the server, FALSE if timeout occured.
|
||||
*/
|
||||
public function ping($timeout = 2);
|
||||
|
||||
/**
|
||||
* Sets whether this connection will use soft commits when comitting.
|
||||
*
|
||||
* Note that this setting only has any effect when using Solr 4.x or higher.
|
||||
*
|
||||
* @param $soft_commit
|
||||
* TRUE if soft commits should be used, FALSE otherwise. Default is FALSE.
|
||||
*/
|
||||
public function setSoftCommit($soft_commit);
|
||||
|
||||
/**
|
||||
* Tells whether this connection will use soft commits when comitting.
|
||||
*
|
||||
* Note that this setting only has any effect when using Solr 4.x or higher.
|
||||
*
|
||||
* @return
|
||||
* TRUE if soft commits will be used, FALSE otherwise.
|
||||
*/
|
||||
public function getSoftCommit();
|
||||
|
||||
/**
|
||||
* Set the stream context to use for requests to the Solr server.
|
||||
*
|
||||
* Must be a valid stream context as created by stream_context_create(). By
|
||||
* default, no special stream context will be used.
|
||||
*
|
||||
* @param resource|null $stream_context
|
||||
* A valid stream context as created by stream_context_create(). Or NULL to
|
||||
* use the default behavior.
|
||||
*/
|
||||
public function setStreamContext($stream_context);
|
||||
|
||||
/**
|
||||
* Returns the stream context to use for requests to the Solr server.
|
||||
*
|
||||
* By default, no special stream context will be used and this method will
|
||||
* return NULL.
|
||||
*
|
||||
* @return resource|null
|
||||
* A valid stream context as created by stream_context_create(). Or NULL if
|
||||
* the default behavior is used.
|
||||
*/
|
||||
public function getStreamContext();
|
||||
|
||||
/**
|
||||
* Gets information about the Solr Core.
|
||||
*
|
||||
* @return array
|
||||
* An array with system information.
|
||||
*/
|
||||
public function getSystemInfo();
|
||||
|
||||
/**
|
||||
* Get metadata about fields in the Solr/Lucene index.
|
||||
*
|
||||
* @param int $num_terms
|
||||
* Number of 'top terms' to return.
|
||||
*
|
||||
* @return array
|
||||
* An array of SearchApiSolrField objects.
|
||||
*/
|
||||
public function getFields($num_terms = 0);
|
||||
|
||||
/**
|
||||
* Gets meta-data about the index.
|
||||
*
|
||||
* @param int $num_terms
|
||||
* Number of 'top terms' to return.
|
||||
*
|
||||
* @return object
|
||||
* A response object filled with data from Solr's Luke.
|
||||
*/
|
||||
public function getLuke($num_terms = 0);
|
||||
|
||||
/**
|
||||
* Gets information about the Solr core.
|
||||
*
|
||||
* @return SimpleXMLElement
|
||||
* A Simple XMl document.
|
||||
*/
|
||||
public function getStats();
|
||||
|
||||
/**
|
||||
* Gets summary information about the Solr Core.
|
||||
*/
|
||||
public function getStatsSummary();
|
||||
|
||||
/**
|
||||
* Clears the cached Solr data.
|
||||
*/
|
||||
public function clearCache();
|
||||
|
||||
/**
|
||||
* Makes a request to a servlet (a path) that's not a standard path.
|
||||
*
|
||||
* @param string $servlet
|
||||
* A path to be added to the base Solr path. e.g. 'extract/tika'.
|
||||
* @param array $params
|
||||
* Any request parameters when constructing the URL.
|
||||
* @param array $options
|
||||
* Options to be passed to drupal_http_request().
|
||||
*
|
||||
* @return object
|
||||
* The HTTP response object.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function makeServletRequest($servlet, array $params = array(), array $options = array());
|
||||
|
||||
/**
|
||||
* Gets the base URL of the Solr server.
|
||||
*
|
||||
* @return string
|
||||
* The base URL of the Solr server.
|
||||
*/
|
||||
public function getBaseUrl();
|
||||
|
||||
/**
|
||||
* Sets the base URL of the Solr server.
|
||||
*
|
||||
* @param string $url
|
||||
* The new base URL of the Solr server.
|
||||
*/
|
||||
public function setBaseUrl($url);
|
||||
|
||||
/**
|
||||
* Sends a raw update request to the Solr server.
|
||||
*
|
||||
* Takes a raw post body and sends it to the update service. Post body should
|
||||
* be a complete and well-formed XML document.
|
||||
*
|
||||
* @param string $rawPost
|
||||
* The XML document to send to the Solr server's update service.
|
||||
* @param int|false $timeout
|
||||
* (optional) Maximum expected duration (in seconds). Defaults to not timing
|
||||
* out.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call
|
||||
*/
|
||||
public function update($rawPost, $timeout = FALSE);
|
||||
|
||||
/**
|
||||
* Adds an array of Solr Documents to the index all at once
|
||||
*
|
||||
* @param array $documents
|
||||
* Should be an array of ApacheSolrDocument instances
|
||||
* @param bool $overwrite
|
||||
* (optional) Set whether existing documents with the same IDs should be
|
||||
* overwritten. Defaults to TRUE.
|
||||
* @param bool $commitWithin
|
||||
* (optional) The time in which the indexed documents should be committed to
|
||||
* the index, in milliseconds. This works in addition to the Solr server's
|
||||
* auto commit settings. Defaults to no additional handling.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function addDocuments(array $documents, $overwrite = NULL, $commitWithin = NULL);
|
||||
|
||||
/**
|
||||
* Sends a commit command to the Solr server.
|
||||
*
|
||||
* Will be synchronous unless $waitSearcher is set to FALSE.
|
||||
*
|
||||
* @param bool $waitSearcher
|
||||
* (optional) Wait until a new searcher is opened and registered as the main
|
||||
* query searcher, making the changes visible. Defaults to true.
|
||||
* @param int|false $timeout
|
||||
* Seconds to wait until timing out with an exception. Defaults to an hour.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function commit($waitSearcher = TRUE, $timeout = 3600);
|
||||
|
||||
/**
|
||||
* Sends a delete request based on a document ID.
|
||||
*
|
||||
* @param string $id
|
||||
* The ID of the document which should be deleted. Expected to be UTF-8
|
||||
* encoded.
|
||||
* @param int|false $timeout
|
||||
* Seconds to wait until timing out with an exception. Defaults to an hour.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function deleteById($id, $timeout = 3600);
|
||||
|
||||
/**
|
||||
* Sends a delete request for several documents, based on the document IDs.
|
||||
*
|
||||
* @param array $id
|
||||
* The IDs of the documents which should be deleted. Expected to be UTF-8
|
||||
* encoded.
|
||||
* @param int|false $timeout
|
||||
* Seconds to wait until timing out with an exception. Defaults to an hour.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function deleteByMultipleIds(array $ids, $timeout = 3600);
|
||||
|
||||
/**
|
||||
* Sends a delete request for all documents that match the given Solr query.
|
||||
*
|
||||
* @param string $rawQuery
|
||||
* The query whose results should be deleted. Expected to be UTF-8 encoded.
|
||||
* @param int|false $timeout
|
||||
* Seconds to wait until timing out with an exception. Defaults to an hour.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function deleteByQuery($rawQuery, $timeout = 3600);
|
||||
|
||||
/**
|
||||
* Sends an optimize command to the Solr server.
|
||||
*
|
||||
* Will be synchronous unless $waitSearcher is set to FALSE.
|
||||
*
|
||||
* @param bool $waitSearcher
|
||||
* (optional) Wait until a new searcher is opened and registered as the main
|
||||
* query searcher, making the changes visible. Defaults to true.
|
||||
* @param int|false $timeout
|
||||
* Seconds to wait until timing out with an exception. Defaults to an hour.
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function optimize($waitSearcher = TRUE, $timeout = 3600);
|
||||
|
||||
/**
|
||||
* Executes a search on the Solr server.
|
||||
*
|
||||
* @param string|null $query
|
||||
* (optional) The raw query string. Defaults to an empty query.
|
||||
* @param array $params
|
||||
* (optional) Key / value pairs for other query parameters (see Solr
|
||||
* documentation). Use arrays for parameter keys used more than once (e.g.,
|
||||
* facet.field).
|
||||
* @param string $method
|
||||
* The HTTP method to use. Must be either "GET" or "POST". Defaults to
|
||||
* "GET".
|
||||
*
|
||||
* @return object
|
||||
* A response object.
|
||||
*
|
||||
* @throws Exception
|
||||
* If an error occurs during the service call.
|
||||
*/
|
||||
public function search($query = NULL, array $params = array(), $method = 'GET');
|
||||
|
||||
/**
|
||||
* Escapes special characters from a Solr query.
|
||||
*
|
||||
* A complete list of special characters in Solr queries can be viewed at
|
||||
* http://lucene.apache.org/java/docs/queryparsersyntax.html#Escaping%20Special%20Characters
|
||||
*
|
||||
* @param string $value
|
||||
* The string to escape.
|
||||
* @param string $version
|
||||
* An integer representing major solr version release.
|
||||
*
|
||||
* @return string
|
||||
* An escaped string suitable for passing to Solr.
|
||||
*/
|
||||
public static function escape($value, $version = 0);
|
||||
|
||||
/**
|
||||
* Escapes a string that should be included in a Solr phrase.
|
||||
*
|
||||
* In contrast to escape(), this only escapes '"' and '\'.
|
||||
*
|
||||
* @param string $value
|
||||
* The string to escape.
|
||||
*
|
||||
* @return string
|
||||
* An escaped string suitable for passing to Solr.
|
||||
*/
|
||||
public static function escapePhrase($value);
|
||||
|
||||
/**
|
||||
* Converts a string to a Solr phrase.
|
||||
*
|
||||
* @param string $value
|
||||
* The string to convert to a phrase.
|
||||
*
|
||||
* @return string
|
||||
* A phrase string suitable for passing to Solr.
|
||||
*/
|
||||
public static function phrase($value);
|
||||
|
||||
/**
|
||||
* Escapes a Search API field name for passing to Solr.
|
||||
*
|
||||
* Since field names can only contain one special character, ":", there is no
|
||||
* need to use the complete escape() method.
|
||||
*
|
||||
* @param string $value
|
||||
* The field name to escape.
|
||||
*
|
||||
* @return string
|
||||
* An escaped string suitable for passing to Solr.
|
||||
*/
|
||||
public static function escapeFieldName($value);
|
||||
|
||||
/**
|
||||
* Gets the current solr version.
|
||||
*
|
||||
* @return int
|
||||
* 1, 3 or 4. Does not give a more detailed version, for that you need to
|
||||
* use getSystemInfo().
|
||||
*/
|
||||
public function getSolrVersion();
|
||||
|
||||
}
|
281
includes/solr_field.inc
Normal file
281
includes/solr_field.inc
Normal file
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Logic around Solr field schema information.
|
||||
*/
|
||||
class SearchApiSolrField {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* Human-readable labels for Solr schema properties.
|
||||
*/
|
||||
public static $schemaLabels = array(
|
||||
'I' => 'Indexed',
|
||||
'T' => 'Tokenized',
|
||||
'S' => 'Stored',
|
||||
'M' => 'Multivalued',
|
||||
'V' => 'TermVector Stored',
|
||||
'o' => 'Store Offset With TermVector',
|
||||
'p' => 'Store Position With TermVector',
|
||||
'O' => 'Omit Norms',
|
||||
'L' => 'Lazy',
|
||||
'B' => 'Binary',
|
||||
'C' => 'Compressed',
|
||||
'f' => 'Sort Missing First',
|
||||
'l' => 'Sort Missing Last',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var stdclass
|
||||
* The original field object.
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* An array of schema properties for this field. This will be a subset of
|
||||
* the SearchApiSolrField::schemaLabels array.
|
||||
*/
|
||||
protected $schema;
|
||||
|
||||
/**
|
||||
* Constructs a field information object.
|
||||
*
|
||||
* @param stdClass $field
|
||||
* A field object from Solr's "Luke" servlet.
|
||||
*/
|
||||
public function __construct($field) {
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw information of the field.
|
||||
*
|
||||
* @return object
|
||||
* A field metadata object.
|
||||
*/
|
||||
public function getRaw() {
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the Solr field, according to the Solr schema.
|
||||
*
|
||||
* Note that field types like "text", "boolean", and "date" are conventions,
|
||||
* but their presence and behavior are entirely determined by the particular
|
||||
* schema.xml file used by a Solr core.
|
||||
*
|
||||
* @return string
|
||||
* The type of the Solr field.
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->field->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of field properties.
|
||||
*
|
||||
* @return array
|
||||
* An array of properties describing the solr schema. The array keys are
|
||||
* single-character codes, and the values are human-readable labels. This
|
||||
* will be a subset of the SearchApiSolrField::schemaLabels array.
|
||||
*/
|
||||
public function getSchema() {
|
||||
if (!isset($this->schema)) {
|
||||
foreach (str_split(str_replace('-', '', $this->field->schema)) as $key) {
|
||||
$this->schema[$key] = isset(self::$schemaLabels[$key]) ? self::$schemaLabels[$key] : $key;
|
||||
}
|
||||
}
|
||||
return $this->schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "dynamic base" of this field.
|
||||
*
|
||||
* This typically looks like 'ss_*, and is used to aggregate fields based on
|
||||
* "hungarian" naming conventions.
|
||||
*
|
||||
* @return string
|
||||
* The mask describing the solr aggregate field, if there is one.
|
||||
*/
|
||||
public function getDynamicBase() {
|
||||
return isset($this->field->dynamicBase) ? $this->field->dynamicBase : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field may be suitable for use as a key field.
|
||||
*
|
||||
* Unfortunately, it seems like the best way to find an actual uniqueKey field
|
||||
* according to Solr is to examine the Solr core's schema.xml.
|
||||
*
|
||||
* @return bool
|
||||
* Whether the field is suitable for use as a key.
|
||||
*/
|
||||
public function isPossibleKey() {
|
||||
return !$this->getDynamicBase()
|
||||
&& !in_array($this->getType(), array('boolean', 'date', 'text'))
|
||||
&& $this->isStored()
|
||||
&& !$this->isMultivalued();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a field is suitable for sorting.
|
||||
*
|
||||
* In order for a field to yield useful sorted results in Solr, it must be
|
||||
* indexed, not multivalued, and not tokenized. It's ok if a field is
|
||||
* tokenized and yields only one token, but there's no general way to check
|
||||
* for that.
|
||||
*
|
||||
* @return bool
|
||||
* Whether the field is suitable for sorting.
|
||||
*/
|
||||
public function isSortable() {
|
||||
return $this->isIndexed()
|
||||
&& !$this->isMultivalued()
|
||||
&& !$this->isTokenized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is indexed.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is indexed, FALSE otherwise.
|
||||
*/
|
||||
public function isIndexed() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['I']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is tokenized.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is tokenized, FALSE otherwise.
|
||||
*/
|
||||
public function isTokenized() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['T']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is stored.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is stored, FALSE otherwise.
|
||||
*/
|
||||
public function isStored() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['S']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is multi-valued.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is multi-valued, FALSE otherwise.
|
||||
*/
|
||||
public function isMultivalued() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['M']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field has stored term vectors.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field has stored term vectors, FALSE otherwise.
|
||||
*/
|
||||
public function isTermVectorStored() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['V']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field has the "termOffsets" option set.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field has the "termOffsets" option set, FALSE otherwise.
|
||||
*/
|
||||
public function isStoreOffsetWithTermVector() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['o']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field has the "termPositions" option set.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field has the "termPositions" option set, FALSE otherwise.
|
||||
*/
|
||||
public function isStorePositionWithTermVector() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['p']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field omits norms when indexing.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field omits norms, FALSE otherwise.
|
||||
*/
|
||||
public function isOmitNorms() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['O']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is lazy-loaded.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is lazy-loaded, FALSE otherwise.
|
||||
*/
|
||||
public function isLazy() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['L']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is binary.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is binary, FALSE otherwise.
|
||||
*/
|
||||
public function isBinary() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['B']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field is compressed.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field is compressed, FALSE otherwise.
|
||||
*/
|
||||
public function isCompressed() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['C']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field sorts missing entries first.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field sorts missing entries first, FALSE otherwise.
|
||||
*/
|
||||
public function isSortMissingFirst() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['f']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this field sorts missing entries last.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the field sorts missing entries last, FALSE otherwise.
|
||||
*/
|
||||
public function isSortMissingLast() {
|
||||
$this->getSchema();
|
||||
return isset($this->schema['l']);
|
||||
}
|
||||
|
||||
}
|
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains the SearchApiSolrHttpTransport class.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Drupal-based implementation of the HTTP transport interface.
|
||||
*
|
||||
* Uses drupal_http_request() for sending the request.
|
||||
*/
|
||||
class SearchApiSolrHttpTransport extends Apache_Solr_HttpTransport_Abstract {
|
||||
|
||||
/**
|
||||
* If set, an HTTP authentification string to use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $http_auth;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param $http_auth
|
||||
* If set, an HTTP authentification string to use.
|
||||
*/
|
||||
public function __construct($http_auth = NULL) {
|
||||
$this->http_auth = $http_auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a GET HTTP operation with an optional timeout and return the response
|
||||
* contents, use getLastResponseHeaders to retrieve HTTP headers
|
||||
*
|
||||
* @param string $url
|
||||
* @param float $timeout
|
||||
* @return Apache_Solr_HttpTransport_Response HTTP response
|
||||
*/
|
||||
public function performGetRequest($url, $timeout = false) {
|
||||
return $this->performHttpRequest('GET', $url, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a HEAD HTTP operation with an optional timeout and return the response
|
||||
* headers - NOTE: head requests have no response body
|
||||
*
|
||||
* @param string $url
|
||||
* @param float $timeout
|
||||
* @return Apache_Solr_HttpTransport_Response HTTP response
|
||||
*/
|
||||
public function performHeadRequest($url, $timeout = false) {
|
||||
return $this->performHttpRequest('HEAD', $url, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a POST HTTP operation with an optional timeout and return the response
|
||||
* contents, use getLastResponseHeaders to retrieve HTTP headers
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $rawPost
|
||||
* @param string $contentType
|
||||
* @param float $timeout
|
||||
* @return Apache_Solr_HttpTransport_Response HTTP response
|
||||
*/
|
||||
public function performPostRequest($url, $rawPost, $contentType, $timeout = false) {
|
||||
return $this->performHttpRequest('POST', $url, $timeout, $rawPost, $contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for making an HTTP request.
|
||||
*/
|
||||
protected function performHttpRequest($method, $url, $timeout, $rawPost = NULL, $contentType = NULL) {
|
||||
$options = array(
|
||||
'method' => $method,
|
||||
'timeout' => $timeout && $timeout > 0 ? $timeout : $this->getDefaultTimeout(),
|
||||
'headers' => array(),
|
||||
);
|
||||
|
||||
if ($this->http_auth) {
|
||||
$options['headers']['Authorization'] = $this->http_auth;
|
||||
}
|
||||
if ($timeout) {
|
||||
$options['timeout'] = $timeout;
|
||||
}
|
||||
if ($rawPost) {
|
||||
$options['data'] = $rawPost;
|
||||
}
|
||||
if ($contentType) {
|
||||
$options['headers']['Content-Type'] = $contentType;
|
||||
}
|
||||
|
||||
$response = drupal_http_request($url, $options);
|
||||
|
||||
$type = isset($response->headers['content-type']) ? $response->headers['content-type'] : 'text/xml';
|
||||
$body = isset($response->data) ? $response->data : NULL;
|
||||
return new Apache_Solr_HttpTransport_Response($response->code, $type, $body);
|
||||
}
|
||||
|
||||
}
|
@@ -11,15 +11,15 @@
|
||||
class SearchApiSpellcheckSolr extends SearchApiSpellcheck {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructs a SearchApiSpellcheckSolr object.
|
||||
*
|
||||
* If solr has returned spelling suggestion then loop through them and add
|
||||
* If Solr has returned spelling suggestion then loop through them and add
|
||||
* them to this spellcheck service.
|
||||
*
|
||||
* @param Apache_Solr_Response $response
|
||||
* @param object $response
|
||||
* The Solr response object.
|
||||
*/
|
||||
function __construct(Apache_Solr_Response $response) {
|
||||
function __construct($response) {
|
||||
if (isset($response->spellcheck->suggestions)) {
|
||||
$suggestions = $response->spellcheck->suggestions;
|
||||
foreach ($suggestions as $word => $data) {
|
||||
|
Reference in New Issue
Block a user