Commit e3b2d3ee authored by Bas de Nooijer's avatar Bas de Nooijer

Merge pull request #373 from basdenooijer/docs

Added docs to repository
parents 3a77a8bf 3780e6c7
......@@ -11,7 +11,7 @@ Please see the project website for a more detailed description.
## Requirements
Solarium only supports PHP 5.3 and up.
Solarium only supports PHP 5.4 and up.
It's highly recommended to have Curl enabled in your PHP environment. However if you don't have Curl available you can
switch from using Curl (the default) to another client adapter. The other adapters don't support all the features of the
Curl adapter.
......@@ -19,19 +19,11 @@ Curl adapter.
## Getting started
The preferred way to install Solarium is by using Composer. Solarium is available on Packagist.
For more info see
http://wiki.solarium-project.org/index.php/V3:Installation#Getting_Solarium
## More information
* Manual
http://wiki.solarium-project.org/index.php/Solarium_3.x_manual
* Project website
http://www.solarium-project.org/
* API docs
http://api.solarium-project.org/
* Docs
See the docs folder
* Issue tracker
http://github.com/solariumphp/solarium/issues
......
Client and adapters
===================
Client
------
The client (class Solarium\\Client) is the main interface of Solarium, a sort of gateway. It holds config settings and has method to access all Solarium functionality. It controls the calling of many underlying Solarium classes but has very little built-in functionality itself.
This allows for a lightweight class, so that you can have it available at all times at very little cost. The Solarium\\Client class uses lazy loading where possible. By having all functionality implemented in subclasses you can also easily customize behaviour by altering the mapping to these subclasses, while still maintaining the same client API.
The name 'Client' might be somewhat confusing. It was chosen because Solarium is a Solr client library and this is the main class. But the client is not actually communicating with Solr. That part is done by the client adapters.
Adapters
--------
The adapters are the actual implementations for communication with Solr. They have a generic interface, but different implementations. They are purely for executing requests, and hold no state.
### Authentication
The Http, Curl and Pecl adapter support authentication. To use this set the authentication on the request object using the setAuthentication() method. For the ZendHttp adapter you set the authentication using the ZendHttp api or config.
Endpoints
---------
An endpoint is basically a collection of settings that define a solr server or core. Each endpoint is defined with a key. For each query you execute you can (optionally) supply an endpoint or endpoint key, and the query is executed using this endpoint, using the client and adapter instance. The first endpoint you define is automatically used as the default endpoint. This makes using a single endpoint easier, as you don’t need to pass it to execute queries. Of course you can always set your own default endpoint if needed.
The endpoint class has a \_\_toString method that output all settings, this can be very useful for debugging or logging.
### Authentication
Endpoints support authentication. To use this set the authentication on the endpoint object using the setAuthentication() method.
Curl adapter
============
This is the standard Solarium adapter. It supports the most features (for instance concurrent requests) and doesn't suffer from memory issues (like the HttpAdapter in some cases). The only downside is that it depends on the PHP Curl extension, however most PHP environment have this extension. If Curl is not available and installing is not an option you should use one of the other adapters.
As this is the default adapter you don't need any settings or API calls to use it.
### Proxy support
The curl adapter support the use of a proxy. Use the adapter option `proxy` to enable this.
PeclHttp adapter
================
The PeclHttp adapter makes use of the [pecl\_http package](http://pecl.php.net/package/pecl_http). So to use this adapter you need to have Pecl Http installed.
The functionality offered by this adapter is the same as the default adapter, but the HTTP requests are executed using Pecl Http.
```php
<?php
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// set the adapter to peclhttp
$client->setAdapter('Solarium\Core\Client\Adapter\PeclHttp');
// get a select query instance
$query = $client->createSelect();
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
HttpAdapter
===========
This adapter has no dependencies on other classes or any special PHP extensions as it uses basic PHP streams. This makes it a safe choice, but it has no extra options. If you need detailed control over your request or response you should probably use another adapter, but for most standard cases it will do just fine.
```php
<?php
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// set the adapter to curl
$client->setAdapter('Solarium\Core\Client\Adapter\Http');
// get a select query instance
$query = $client->createSelect();
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
ZendHttp adapter
================
The ZendHttp adapter makes use of the Zend\_Http component in Zend Framework (version 1). So to use this adapter you need to have ZF available. By using Zend\_Http all the features of this component are available:
- multiple adapter implementations
- keepalive
- cookies / sessions
- redirection support
- http authentication
- and much more, see the [http://framework.zend.com/manual/en/zend.http.html Zend Http manual](http://framework.zend.com/manual/en/zend.http.html_Zend_Http_manual "wikilink")
The base functionality is the same as the default adapter. The only difference is that this adapter allows you to set Zend\_Http options and also offers access to the Zend\_Http instance.
```php
<?php
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// set the adapter to zendhttp and get a zendhttp client instance reference
$client->setAdapter('Solarium\Core\Client\Adapter\ZendHttp');
$zendHttp = $client->getAdapter()->getZendHttp();
// you can use any of the zend_http features, like http-authentication
$zendHttp->setAuth('user', 'password!', Zend_Http_Client::AUTH_BASIC);
// get a select query instance
$query = $client->createSelect();
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
Custom adapter
==============
You can also use a custom adapter, with these steps:
- Create your custom adapter class. It should implement Solarium\\Core\\Client\\Adapter\\AdapterInterface.
- You can take a look at the existing implementations as an example.
- Make sure your class is available to Solarium, by including it manually or through autoloading.
- Call the 'setAdapter' method on your Solarium client instance with your own adapters' classname as argument (or use the 'adapter' config setting)
- Now use Solarium as you normally would, all communication to Solr will be done using your adapter. The adapter class will only be instantiated on the first communication to Solr, not directly after calling 'setAdapter' (lazy loading)
Customizing Solarium
====================
Solarium was designed to be highly customizable, in the following ways:
1. by allowing for partial usage, for instance only convert a query into a request object but handle the communication in your own code
2. by adding an event dispatcher for plugins
3. and also still supporting the extending of classes (Solarium doesn't use 'private' or 'final' anywhere)
What method of customization to use depends on your case:
- if you want to use only some parts of Solarium, but not modify it, go with method 1
- if you want to customize solarium by altering/adding behaviour use the plugin structure. This has many advantages over extending:
- Plugins are easily reusable
- You can combine multiple plugins
- By leaving your Solarium library stock you can add plugins developed by others without issues
- Plugins can easily be disabled, for instance in case of issues or for debugging
- No issues with upgrading Solarium
- A very basic plugin could even be implemented using a closure, so plugins are not hard to use!
- if for some reason method 2 fails, or you really favor extending, that's of course still possible. But the preferred method is using the plugin structure.
Partial usage
=============
Normally you execute your query using the corresponding method in the client class. For instance for a select query you use the select($query) method. This methods map to the execute method, which executes the steps needed to get the query response. It is also possible to call these methods yourself. This way you can execute only a part of the query flow, or alter the data in between calls (but in that case a plugin might be a better choice).
The example code shows how to do this. It also shows how to generate the URI for a query string, something that's requested a lot. To show all methods the example continues after getting the URI, but at this point you could of course also switch to some custom code.
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// This example shows how to manually execute the query flow.
// By doing this manually you can customize data in between any step (although a plugin might be better for this)
// And you can use only a part of the flow. You could for instance use the query object and request builder,
// but execute the request in your own code.
// create a client instance
$client = new Solarium\Client($config);
// create a select query instance
$query = $client->createSelect();
// manually create a request for the query
$request = $client->createRequest($query);
// you can now use the request object for getting an uri (ie. to use in you own code)
// or you could modify the request object
echo 'Request URI: ' . $request->getUri() . '<br/>';
// you can still execute the request using the client and get a 'raw' response object
$response = $client->executeRequest($request);
// and finally you can convert the response into a result
$result = $client->createResult($query, $response);
// display the total number of documents found by solr
echo 'NumFound: '.$result->getNumFound();
// show documents using the resultset iterator
foreach ($result as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
Plugin system
=============
The Solarium plugin has several features:
- custom plugin code can be executed for events
- events give access to relevant vars, for reading but also to optionally modify them
- plugins have access to the Solarium client instance they belong to, so you can also modify Solarium settings and class mappings in a plugin
By combining these options you can achieve almost any type of customization with a plugin.
Solarium uses a separate library (included using Composer) for events. For more info on the Event Dispatcher take a look at [http://symfony.com/doc/2.0/components/event\_dispatcher/introduction.html the docs](http://symfony.com/doc/2.0/components/event_dispatcher/introduction.html_the_docs)
This example shows all available events and how to use the events to create a very basic debugger: ```php
<?php
require(__DIR__.'/init.php');
use Solarium\Core\Event\Events;
// this very simple plugin shows a timing for each event and display some request debug info
class BasicDebug extends Solarium\Core\Plugin\Plugin
{
protected $start;
protected $output = array();
protected function initPluginType()
{
$this->start = microtime(true);
$dispatcher = $this->client->getEventDispatcher();
$dispatcher->addListener(Events::PRE_CREATE_REQUEST, array($this, 'preCreateRequest'));
$dispatcher->addListener(Events::POST_CREATE_REQUEST, array($this, 'postCreateRequest'));
$dispatcher->addListener(Events::PRE_EXECUTE_REQUEST, array($this, 'preExecuteRequest'));
$dispatcher->addListener(Events::POST_EXECUTE_REQUEST, array($this, 'postExecuteRequest'));
$dispatcher->addListener(Events::PRE_CREATE_RESULT, array($this, 'preCreateResult'));
$dispatcher->addListener(Events::POST_CREATE_RESULT, array($this, 'postCreateResult'));
$dispatcher->addListener(Events::PRE_EXECUTE, array($this, 'preExecute'));
$dispatcher->addListener(Events::POST_EXECUTE, array($this, 'postExecute'));
$dispatcher->addListener(Events::PRE_CREATE_QUERY, array($this, 'preCreateQuery'));
$dispatcher->addListener(Events::POST_CREATE_QUERY, array($this, 'postCreateQuery'));
}
protected function timer($event)
{
$time = round(microtime(true) - $this->start, 5);
$this->output[] = '['.$time.'] ' . $event;
}
public function display()
{
echo implode('<br/>', $this->output);
}
public function preCreateRequest()
{
$this->timer('preCreateRequest');
}
public function postCreateRequest()
{
$this->timer('postCreateRequest');
}
// This method uses the aviable param(s) (see plugin abstract class)
// You can access or modify data this way
public function preExecuteRequest($event)
{
$this->timer('preExecuteRequest');
// this dummy param will be visible in the debug output but will also be used in the actual Solr request
$event->getRequest()->addParam('dummyparam', 'dummyvalue');
$this->output[] = 'Request URI: ' . $event->getRequest()->getUri();
}
public function postExecuteRequest()
{
$this->timer('postExecuteRequest');
}
public function preCreateResult()
{
$this->timer('preCreateResult');
}
public function postCreateResult()
{
$this->timer('postCreateResult');
}
public function preExecute()
{
$this->timer('preExecute');
}
public function postExecute()
{
$this->timer('postExecute');
}
public function preCreateQuery()
{
$this->timer('preCreateResult');
}
public function postCreateQuery()
{
$this->timer('postCreateResult');
}
}
htmlHeader();
// create a client instance and register the plugin
$plugin = new BasicDebug();
$client = new Solarium\Client($config);
$client->registerPlugin('debugger', $plugin);
// execute a select query and display the results
$query = $client->createSelect();
$resultset = $client->select($query);
echo 'NumFound: '.$resultset->getNumFound();
foreach ($resultset as $document) {
echo '<hr/><table>';
foreach ($document as $field => $value) {
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
// display the debug plugin output
echo '<hr/><h1>Plugin output</h1>';
$plugin->display();
htmlFooter();
```
The second example shows how to replace the built-in select querytype with a custom implementation: ```php
<?php
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\Core\Plugin\Plugin;
use Solarium\QueryType\Select\Query\Query as Select;
// This is a custom query class that could have some customized logic
class MyQuery extends Select
{
// ...customization here...
}
// this very simple plugin that modifies the default querytype mapping
class QueryCustomizer extends Plugin
{
public function initPlugin($client, $options)
{
$client->registerQueryType(
Client::QUERY_SELECT,
'MyQuery'
);
}
}
htmlHeader();
// create a client instance and register the plugin
$client = new Client($config);
$client->registerPlugin('querycustomizer', 'QueryCustomizer');
// create a select query instance
$query = $client->createSelect();
// check the query class, it should be our custom query class
echo 'Query class: ' . get_class($query) . '<br/>';
// execute the query and display the results
$resultset = $client->select($query);
echo 'NumFound: '.$resultset->getNumFound();
foreach ($resultset as $document) {
echo '<hr/><table>';
foreach ($document as $field => $value) {
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
Extending Solarium classes
==========================
You can extend any class in Solarium, there is no use of 'private' or 'final'. However, Solarium does have several built-in class mappings for factory methods. Most important are the querytype mapping in Solarium\\Client and the component mapping in Solarium\\QueryType\\Select\\Query\\Query. In some cases you might need to alter this mappings for your classes to be used.
Other than that, there are no special issues to be expected. You can extend Solarium classes like any other PHP class.
If your use case can be solved using plugins that is probably the safest choice, as by extending classes you gain access to non-public methods in the API. These are subject to change in future releases, where the public API is not (except for major releases).
\ No newline at end of file
Documents
=========
The Solarium document classes represent the documents in Solr indexes. Solarium has two built-in document classes, one included with the select query for reading data and one for updating data in the update query.
The document fieldnames are related to your Solr index schema. When reading documents from Solr all stored fields will be returned automatically. When updating data you need to add the correct fields to the document, the document object has no knowledge of the schema.
In the following sections the usage of both document types and the use of custom documents is described.
Read-only document
==================
This is the default document type for a select query result. This is an immutable object that allows access to the field values by name or by iterating over the document. This object implements the `Iterator`, `Countable` and `ArrayAccess` interfaces. You can use the document in multiple ways:
- access fields as object vars (fieldname as varname)
- access fields as array entries (fieldname as key)
- iterate over all fields (returning fieldnames as 'key' and the fieldvalue as 'value')
- count it (returns the nr. of fields in the document)
The example belows shows all these options.
To enforce the immutable state of this document type an exception will be thrown if you try to alter a field value. For an updateable document you should use this class: Solarium\\QueryType\\Update\\Query\\Document
Solarium uses this document type as default for select queries for two reasons:
- in most cases no update functionality is needed, so it will only be overhead
- to discourage the use of Solr as a DB, as in reading - altering - saving. Almost all schemas have index-only fields. There is no way to read the value of there fields, so this data will be lost when re-saving the document! Updates should normally be done based on your origin data (i.e. the database). If you are *really sure* you want to update Solr data, you can set a read-write document class as the document type for your select query, alter the documents and use them in an update query.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createQuery($client::QUERY_SELECT);
// this executes the query and returns the result
$resultset = $client->execute($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
Read-write document
===================
This document type can be used for update queries. It extends the Read-Only document and adds the ability to add, set or remove field values and boosts.
Any fields you set must exactly match the field names in your Solr schema, or you will get an exception when you try to add them.
You can set field values in multiple ways:
- as object property
- as array entry
- by using the `setField` and `addField` methods
See the API docs for details and the example code below for examples.
Multivalue fields
-----------------
If you set field values by property, array entry or by using the `setField` method you need to supply an array of values for a multivalue field. Any existing field values will be overwritten.
If you want to add an extra value to an existing field, without overwriting, you should use the `addField` method. If you use this method on a field with a single value it will automatically be converted into a multivalue field, preserving the current value. You will need to call this method once for each value you want to add, it doesn't support arrays. You can also use this method for creating a new field, so you don't need to use a special method for the first field value.
Dates
-----
If you have a date in your Solr schema you can set this in the document as a string in the Solr date format. However, you can also set a PHP DateTime object as the field value in your document. In that case Solarium will automatically convert it to a datetime string in the correct format.
Atomic updates
--------------
You can create atomic updates by using the setFieldModifier method. Set a modifier on the field you want to update. The supported modifiers are:
- MODIFIER\_SET
- MODIFIER\_ADD
- MODIFIER\_INC
The addField and setField methods also support modifiers as an optional argument. Any document that uses modifiers MUST have a key, you can set the key using the setKey method.
A document with atomic updates can be added to an update query just like any other document.
For more info on Solr atomic updates please read the manual: <http://wiki.apache.org/solr/Atomic_Updates>
Versioning
----------
The document has getVersion() and setVersion methods. By default no version is used, but you can set a version manually. There is a set of predefined values:
- VERSION\_DONT\_CARE
- VERSION\_MUST\_EXIST
- VERSION\_MUST\_NOT\_EXIST
But you can also set a custom version (specific ID).
For more info on versioning please see this blogpost: <http://yonik.com/solr/optimistic-concurrency/>
Boosts
------
There are two types of boosts: a document boost and a per-field boost. See Solr documentation for the details about index-time boosts. *Do not confuse these with query-time boosts (term^2)*
You can set the document boost with the `setBoost` method.
Field boosts can be set with the `setFieldBoost` method, or with optional parameters of the `setField` and `addField` methods. See the API docs for details.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// create a new document for the data
$doc1 = $update->createDocument();
$doc1->id = 123;
$doc1->name = 'testdoc-1';
$doc1->price = 364;
// and a second one
$doc2 = $update->createDocument();
$doc2->id = 124;
$doc2->name = 'testdoc-2';
$doc2->price = 340;
// add the documents and a commit command to the update query
$update->addDocuments(array($doc1, $doc2));
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
Custom document
===============
You can easily use your own 'document' types, for instance to directly map Solr results to entity models. You need to do the following:
- make sure the class is available (already loaded or can be autoloaded)
- set the 'documentclass' option of your query to your own classname
- the class must implement the same interface as the original document class.
\ No newline at end of file
Getting started
===============
In this part the installation of Solarium is covered and a quick-start with some simple queries. If you intend to read the rest of the manual you might skip the example queries, they will be covered in-depth in their own chapters.
Installation
============
### Requirements
For installing Solarium a minimal PHP version 5.3 is required. While previous Solarium versions with any PHP5 version, Solarium 3 uses interfaces so 5.3+ is a hard requirement.
There is no Solr version requirement. Solr versions 1.4 and upwards have been tested with Solarium. Ofcourse, if you want to use version specific features like spatial search you need the right Solr version. For spatial search you will need at least 3.1.
### Getting Solarium
There are several ways to get Solarium. The preferred method is by using Composer. Alternatively you can download a prepacked release from GitHub, or use git. Only Composer is described here.
First of all, if you're not familiar with Composer take a look here: [<http://getcomposer.org>](http://getcomposer.org). Composer is quickly becoming the standard for handling dependencies in PHP apps and many libraries support it. As of version 3 Solarium depends on an external library, the Symfony Event Dispatcher component. Composer automatically manages this dependency.
See [<https://packagist.org>](https://packagist.org) for other packages.
- Make sure you have composer available / installed (see the getting started section on the Composer site)
- Add Solarium to your composer.json file. It should look something like this:
`  {`
`      "require": {`
`          "solarium/solarium": "2.4.0"`
`      }`
`  }`
- Run composer install
- Make sure to use the composer autoloader, and Solarium should be available.
**Only if you don't use composer:** you need to use a PSR-0 autoloader, or the supplied autoloader: ```php
```
Also you need to make sure the the Symfony Event Dispatcher component is available.
### Checking the availability
To check your installation you can do a Solarium version check with the following code. If everything works you should see the version of Solarium you downloaded. To test Solr communication you can use a ping query (you might need some configuration to get the ping working, more on that later) ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// check solarium version available
echo 'Solarium library version: ' . Solarium\Client::VERSION . ' - ';
// create a client instance
$client = new Solarium\Client($config);
// create a ping query
$ping = $client->createPing();
// execute the ping query
try {
$result = $client->ping($ping);
echo 'Ping query successful';
echo '<br/><pre>';
var_dump($result->getData());
echo '</pre>';
} catch (Solarium\Exception $e) {
echo 'Ping query failed';
}
htmlFooter();
```
### Available integrations
Some users of Solarium have been nice enough to create easy ways of integrating Solarium:
- A Solarium bundle for Symfony2 <https://github.com/nelmio/NelmioSolariumBundle>
- Zend Framework 2 module <https://zfmodules.com/Ewgo/SolariumModule>
- Lithium <https://github.com/joseym/li3_solr>
- Fuel PHP <https://github.com/bgrimes/fuelphp-solarium>
- Yii <https://github.com/estahn/YiiSolarium>
- Magento <https://github.com/jeroenvermeulen/magento-solarium>
- Wordpress <https://github.com/pantheon-systems/solr-for-wordpress>
If you know of any other integrations please let it know!
Basic usage
===========
All the code display below can be found in the /examples dir of the project, where you can also easily execute the code. For more info see [Example code](V3:Example_code "wikilink").
All the examples use the init.php file. This file registers the Solarium autoloader and also loads the $config array for use in the client constructor. The $config array has the following contents: ```php
<?php
$config = array(
'endpoint' => array(
'localhost' => array(
'host' => '127.0.0.1',
'port' => 8983,
'path' => '/solr/',
)
)
);
```
### Selecting documents
This is the basic example of executing a select query and displaying the results: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createQuery($client::QUERY_SELECT);
// this executes the query and returns the result
$resultset = $client->execute($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
See the docs for all options.
### Facet field
This example demonstrates a facet field.
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet field instance and set options
$facetSet->createFacetField('stock')->setField('inStock');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
### Deleting documents
Documents can be deleted with a query: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete query and a commit command to the update query
$update->addDeleteQuery('name:testdoc*');
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
Or by id ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete id and a commit command to the update query
$update->addDeleteById(123);
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
Also, a combination of both is possible. See the docs for more info.
### Adding documents
This example adds some documents to the index: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// create a new document for the data
$doc1 = $update->createDocument();
$doc1->id = 123;
$doc1->name = 'testdoc-1';
$doc1->price = 364;
// and a second one
$doc2 = $update->createDocument();
$doc2->id = 124;
$doc2->name = 'testdoc-2';
$doc2->price = 340;
// add the documents and a commit command to the update query
$update->addDocuments(array($doc1, $doc2));
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
For all options (like boosting) see the docs.
Example code
============
With Solarium a set of examples is included to demonstrate the usage and to test your Solr environment. To get the examples working you need to do the following:
1. make the /examples folder browseable on your (test)webserver.
2. download a standard Solr release and start the included Jetty example (see the Solr example/README.txt file)
3. load the demo data into the example index (again see the Solr example/README.txt file)
4. open the example dir in a browser, the index.html file listing all available examples should show up
That's all! The default config file of the examples was made for the standard Solr example included with a Solr release. If you want to use a custom Solr environment you can copy the file 'config.dist.php' in the example dir to 'config.php' and correct the settings. Your environment needs to have the default Solr example schema and data for the examples to work.
If examples for some Solarium functionality are missing please request them by opening an issue in the issue tracker: [<http://github.com/basdenooijer/solarium/issues>](http://github.com/basdenooijer/solarium/issues)
\ No newline at end of file
Solarium documentation
=================
Solarium is a Solr client library for PHP. It is developed with these goals in mind:
- Releave developers of the ‘raw communication’ with Solr, ie. setting params, building strings, hiding all this with an easy to use API, allowing you to focus on business logic.
- Allow for reuse, for instance a query can be extended to modify it
- Be flexible. For instance the query and result models are not tied to a specific Solr client implementation. There are multiple Solr Client adapters for Solr communication. All models can be extended by your own implementation if needed and a plugin system is available.
- Be usable in any PHP application. No dependencies on other frameworks. Solarium tries to follow the Symfony 2 standard and integrates nicely with SF2, but doesn’t in rely on it. You can use Solarium just as easily in Zend Framework or any other PHP framework.
- Accurately model Solr. For instance the updating of a Solr index. Most clients have separate add, delete and commit methods that also issue separate requests. But Solr actually has an update handler that supports all those actions in a single request. The model should reflect this while keeping it easy to use.
- Find a good balance between nice and feature-rich code and performance. A library/framework for general use will never be as fast as a custom implementation that only contains the bare minimum for your use case. But the performance difference between the two should be at a reasonable level. And because of the dynamic nature of PHP the models can’t be too extensive, yet they should not be over-simplified.
- Only implement basic functionality in the standard models. All additional functionality should be in separate code that only gets loaded when used. This benefits performance, but also helps to prevent classes with huge APIs. The query components and plugins are a good example.
Example code
------------
This is a basic example that executes a simple select query with one facet and displays the results:
```php
$client = new Solarium\Client($config);
$query = $client->createSelect();
$facetSet = $query->getFacetSet();
$facetSet->createFacetField('stock')->setField('inStock');
$resultset = $client->select($query);
echo 'NumFound: '.$resultset->getNumFound() . PHP_EOL;
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']' . PHP_EOL;
}
foreach ($resultset as $document) {
echo $document->id . PHP_EOL;
echo $document->name . PHP_EOL;
}
```
\ No newline at end of file
Plugins
=======
Solarium offers a plugin system to allow for easy extension by users. But plugins are also used by Solarium itself to keep optional features from bloating the main code base. In this section the standard plugins are documented.
BufferedAdd plugin
==================
When you need to do a lot of document inserts or updates, for instance a bulk update or initial indexing, it’s most efficient to do this in batches. This makes a lot more difference than you might think, for some benchmarks see [http://www.raspberry.nl/2011/04/08/solr-update-performance/ this blogpost](http://www.raspberry.nl/2011/04/08/solr-update-performance/_this_blogpost "wikilink").
This can be done very easily with this plugin, you can simply keep feeding documents, it will automatically create batch update queries for you.
Some notes:
- You can set a custom buffer size. The default is 100 documents, a safe value. By increasing this you can get even better performance, but depending on your document size at some level you will run into memory or request limits. A value of 1000 has been successfully used for indexing 200k documents.
- You can use the createDocument method with array input, but you can also manually create document instance and use the addDocument(s) method.
- With buffer size X an update request with be sent to Solr for each X docs. You can just keep feeding docs. These buffer flushes don’t include a commit. This is done on purpose. You can add a commit when you’re done, or you can use the Solr auto commit feature.
- When you are done with feeding the buffer you need to manually flush it one time. This is because there might still be some docs in the buffer that haven’t been flushed yet.
- Alternatively you can end with a commit call. This will also flush the docs, and adds a commit command.
- The buffer also has a clear method to reset the buffer contents. However documents that have already been flushed cannot be cleared.
- Using the 'setEndpoint' method you can select which endpoint should be used. If you don't set a specific endpoint, the default endpoint of the client instance will be used.
Events
------
### solarium.bufferedAdd.addDocument
For each document that is added an 'AddDocument' event is triggered. This even has access to the document being added.
### solarium.bufferedAdd.preFlush
Triggered just before a flush. Has access to the document buffer and overwrite and commitWithin settings
### solarium.bufferedAdd.postFlush
Triggered just after a flush. Has access to the flush (update query) result
### solarium.bufferedAdd.preCommit
Triggered just before a commit. Has access to the document buffer and all commit settings
### solarium.bufferedAdd.postCommit
Triggered just after a commit. Has access to the commit (update query) result
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
use Solarium\Plugin\BufferedAdd\Event\Events;
use Solarium\Plugin\BufferedAdd\Event\PreFlush as PreFlushEvent;
htmlHeader();
// create a client instance and autoload the buffered add plugin
$client = new Solarium\Client($config);
$buffer = $client->getPlugin('bufferedadd');
$buffer->setBufferSize(10); // this is quite low, in most cases you can use a much higher value
// also register an event hook to display what is happening
$client->getEventDispatcher()->addListener(
Events::PRE_FLUSH,
function (PreFlushEvent $event) {
echo 'Flushing buffer (' . count($event->getBuffer()) . 'docs)<br/>';
}
);
// let's insert 25 docs
for ($i=1; $i<=25; $i++) {
// create a new document with dummy data and add it to the buffer
$data = array(
'id' => 'test_'.$i,
'name' => 'test for buffered add',
'price' => $i,
);
$buffer->createDocument($data);
// alternatively you could create document instances yourself and use the addDocument(s) method
}
// At this point two flushes will already have been done by the buffer automatically (at the 10th and 20th doc), now
// manually flush the remainder. Alternatively you can use the commit method if you want to include a commit command.
$buffer->flush();
// In total 3 flushes (requests) have been sent to Solr. This should be visible in the output of the event hook.
htmlFooter();
```
CustomizeRequest plugin
=======================
Solarium has support for the most used features in Solr. But if you need to use a feature not yet supported by Solarium, or even a custom Solr extension, you can use this plugin to manually add params to the request.
This plugin allows you to manually add two settings:
- GET params
- HTTP headers
GET params and headers by default are only applied to the next request, but optionally you can make them persistent so they are applied to every request. For GET params you can also set an option to overwrite any existing value(s) with the same name in the original request.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and autoload the customize request plugin
$client = new Solarium\Client($config);
$customizer = $client->getPlugin('customizerequest');
// add a persistent HTTP header (using array input values)
$customizer->createCustomization(
array(
'key' => 'auth',
'type' => 'header',
'name' => 'X-my-auth',
'value' => 'mypassword',
'persistent' => true
)
);
// add a persistent GET param (using fluent interface)
$customizer->createCustomization('session')
->setType('param')
->setName('ssid')
->setValue('md7Nhd86adye6sad46d')
->setPersistent(true);
// add a GET param thats only used for a single request (the default setting is no persistence)
$customizer->createCustomization('id')
->setType('param')
->setName('id')
->setValue(4576);
// create a basic query to execute
$query = $client->createSelect();
// execute query (you should be able to see the extra params in the solr log file)
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound() . '<br/>';
// execute the same query again (this time the 'id' param should no longer show up in the logs)
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
htmlFooter();
```
LoadBalancer plugin
===================
This plugin is a code based loadbalancer for when you do need the redundancy and extra performance of multiple Solr servers but have not yet grown to the point where you have dedicated loadbalancers. The main features of this plugin are:
- support for multiple servers, each with their own ‘weight’
- ability to use a failover mode (try another server on query failure)
- block querytypes from loadbalancing (update queries are blocked by default)
- force a specific server for the next query
All blocked query types (updates by default) are excluded from loadbalancing so they will use the default adapter settings that point to the master. All other queries will be load balanced.
Events
------
### solarium.loadbalancer.endpointFailure
An 'EndpointFailure' event is triggered when a HTTP exception occurs on one of the backends. This event has access to the Endpoint object and the exception that occurred.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and create endpoints
$client = new Solarium\Client($config);
$endpoint1 = $client->createEndpoint('local1'); //normally you would add endpoint specific settings...
$endpoint2 = $client->createEndpoint('local2');
$endpoint3 = $client->createEndpoint('local3');
// get loadbalancer plugin instance and add endpoints
$loadbalancer = $client->getPlugin('loadbalancer');
$loadbalancer->addEndpoint($endpoint1, 100);
$loadbalancer->addEndpoint($endpoint2, 100);
$loadbalancer->addEndpoint($endpoint3, 1);
// create a basic query to execute
$query = $client->createSelect();
// execute the query multiple times, displaying the server for each execution
for ($i = 1; $i <= 8; $i++) {
$resultset = $client->select($query);
echo 'Query execution #' . $i . '<br/>';
echo 'NumFound: ' . $resultset->getNumFound(). '<br/>';
echo 'Server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
}
// force a server for a query (normally solr 3 is extremely unlikely based on its weight)
$loadbalancer->setForcedEndpointForNextQuery('local3');
$resultset = $client->select($query);
echo 'Query execution with server forced to local3<br/>';
echo 'NumFound: ' . $resultset->getNumFound(). '<br/>';
echo 'Server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
// test a ping query
$query = $client->createPing();
$client->ping($query);
echo 'Loadbalanced ping query, should display a loadbalancing server:<br/>';
echo 'Ping server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
// exclude ping query from loadbalancing
$loadbalancer->addBlockedQueryType(Solarium\Client::QUERY_PING);
$client->ping($query);
echo 'Non-loadbalanced ping query, should not display a loadbalancing server:<br/>';
echo 'Ping server: ' . $loadbalancer->getLastEndpoint() .'<hr/>';
htmlFooter();
```
MinimumScoreFilter plugin
=========================
The MinimumScoreFilter plugin allows you to filter a resultset on a minimum score, calculated using the maxScore and a given ratio. For instance, if you set a ratio of 0.5 and the best scoring document has a score of 1.2, all documents scoring less than 0.6 will be filtered.
There are two modes of filtering, removing or just marking. In the example below the marking mode is used and the examples is pretty much self explanatory. In remove mode documents not meeting the required score are not returned at all.
Some important notes:
1. numFound, facet counts and other Solr data is not adjusted for the filtered documents. Just the document resultset is being filtered, this is done by Solarium AFTER getting standard search results from Solr. If you want to count the number of documents after filtering you would have to do that yourself, by iterating all results after filtering.
2. Rows and start (paging and offset) still work, but again this is not adjusted for filtering. So if you sets rows to 10, you might get less because of the filtering.
3. While it's not strictly necessary, you should sort by score as this is much more efficient. This also fits with the expected use case of getting only the best scoring documents.
4. Result document marking is done using a decorator, so you should still be able to use a custom document class.
5. Be aware of the issues related to 'normalizing' scores: [http://wiki.apache.org/lucene-java/ScoresAsPercentages more info](http://wiki.apache.org/lucene-java/ScoresAsPercentages_more_info "wikilink"). This filter only uses score to calculate a the relevancy relative to the best result and doesn't return this calculated score, but be sure to test your results! In cases like an autocomplete or 'best-bet' type of search this filter can be very useful.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// enable the plugin and get a query instance
$filter = $client->getPlugin('minimumscorefilter');
$query = $client->createQuery($filter::QUERY_TYPE);
$query->setQuery('a');
$query->setFields(array('id'));
$query->setFilterRatio(.5);
$query->setFilterMode($query::FILTER_MODE_MARK);
// this executes the query and returns the result
$resultset = $client->execute($query);
// display the total number of documents found by solr and the maximum score
echo 'NumFound: '.$resultset->getNumFound();
echo '<br/>MaxScore: '.$resultset->getMaxScore();
// show documents using the resultset iterator
foreach ($resultset as $document) {
// by setting the FILTER_MARK option we get a special method to test each document
if ($document->markedAsLowScore()) {
echo '<hr/><b>MARKED AS LOW SCORE</b><table>';
} else {
echo '<hr/><table>';
}
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
ParallelExecution plugin
========================
This plugin makes it possible to execute multiple Solr queries at the same time, instead of one after the other. For a use case where you need to execute two queries the performance gain can be very big, my tests show close to 50% improvement. This can be very useful if you need to query several Solr instances or get the results for multiple queries.
Some important notes:
- This plugin makes use of the curl client adapter and calls curl\_multi\_exec, so you do need to have curl available in your PHP environment to be able to use it.
- Only request execution is parallel, requests preparation and result parsing cannot be done parallel. Luckily these parts cost very little time, far more time is in the requests.
- The execution time is limited by the slowest request. If you execute 3 queries with timings of 0.2, 0.4 and 1.2 seconds the execution time for all will be (near) 1.2 seconds.
- If one of the requests fails the other requests will still be executed and the results parsed. In the result array the entry for the failed query will contain an exception instead of a result object. It’s your own responsibility to check the result type.
- All query types are supported, and you can even mix query types in the same execute call.
- For testing this plugin you can use a special Solr delay component I’ve created (and used to develop the plugin). For more info see [http://www.raspberry.nl/2012/01/04/solr-delay-component/ this blog post](http://www.raspberry.nl/2012/01/04/solr-delay-component/_this_blog_post "wikilink").
- Add queries using the addQuery method. Supply at least a key and a query instance. Optionally you can supply a client instance as third argument. This can be used to execute queries on different cores or even servers. If omitted the plugin will use it's own client instance.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and autoload the customize request plugin
$client = new Solarium\Client($config);
$parallel = $client->getPlugin('parallelexecution');
// Add a delay param to better show the effect, as an example Solr install with
// only a dozen documents is too fast for good testing
// This param only works with the correct Solr plugin,
// see http://www.raspberry.nl/2012/01/04/solr-delay-component/
// If you don't have to plugin the example still works, just without the delay.
$customizer = $client->getPlugin('customizerequest');
$customizer->createCustomization(
array(
'key' => 'delay',
'type' => 'param',
'name' => 'delay',
'value' => '500',
'persistent' => true
)
);
// create two queries to execute in an array. Keys are important for fetching the results later!
$queryInstock = $client->createSelect()->setQuery('inStock:true');
$queryLowprice = $client->createSelect()->setQuery('price:[1 TO 300]');
// first execute the queries the normal way and time it
$start = microtime(true);
$client->execute($queryInstock);
$client->execute($queryLowprice);
echo 'Execution time for normal "serial" execution of two queries: ' . round(microtime(true)-$start, 3);
echo '<hr/>';
// now execute the two queries parallel and time it
$start = microtime(true);
$parallel->addQuery('instock', $queryInstock);
$parallel->addQuery('lowprice', $queryLowprice);
$results = $parallel->execute();
echo 'Execution time for parallel execution of two queries: ' . round(microtime(true)-$start, 3);
htmlFooter();
// Note: for this example on a default Solr index (with a tiny index) running on localhost the performance gain is
// minimal to none, sometimes even slightly slower!
// In a realworld scenario with network latency, a bigger dataset, more complex queries or multiple solr instances the
// performance gain is much more.
```
PostBigRequest plugin
=====================
If you use complex Solr queries with lots of facets and/or filterqueries the total length of your querystring can exceed the default limits of servlet containers. One solution is to alter your servlet container configuration to raise this limit. But if this is not possible or desired this plugin is another way to solve the problem.
This plugin can automatically convert query execution from using a GET request to a POST request if the querystring exceeds a length limit. Solr also accepts it’s input in the POST data and this usually has a much higher limit.
For instance in Jetty the default ‘headerBufferSize’ is 4kB. Tomcat has a similar setting ‘maxHttpHeaderSize’, also 4kB by default. This limit applies to all the combined headers of a request, so it’s not just the querystring. In comparison, the default for POST data in tomcat (‘maxPostSize’) is 4MB. Jetty uses a ‘maxFormContentSize’ setting with a lower default value of 200kB, but still way higher than the header limit and well above the length of even the most complex queries.
The plugin only uses the length of the querystring to determine the switch to a POST request. Other headers are not included in the length calculation so your limit should be somewhat lower than the limit of the servlet container to allow for room for other headers. This was done to keep the length calculation simple and fast, because the exact headers used can vary for the various client adapters available in Solarium. You can alter the maxquerystringlength by using a config setting or the API. Only GET requests are switched over to POST, if the request already uses the POST method (for instance update queries) it’s not altered.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance and autoload the postbigrequest plugin
$client = new Solarium\Client($config);
$client->getPlugin('postbigrequest');
// create a basic query to execute
$query = $client->createSelect();
// add a huge filterquery to create a very long query string
// note: normally you would use a range for this, it's just an easy way to create a very big querystring as a test
$fq = '';
for ($i = 1; $i <= 1000; $i++) {
$fq .= ' OR price:'.$i;
}
$fq = substr($fq, 4);
$query->createFilterQuery('fq')->setQuery($fq);
// without the plugin this query would fail as it is bigger than the default servlet container header buffer
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
PrefetchIterator plugin
=======================
This plugin can be used for iterating a big resultset. It has an iterator interface and will fetch the results from Solr when needed, in batches of a configurable size (sequential prefetching). You can even iterate all the documents in a Solr index.
It’s very easy to use. You configure a query like you normally would and pass it to the plugin. See the example code below.
Example usage
-------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setFields(array('id'));
// get a plugin instance and apply settings
$prefetch = $client->getPlugin('prefetchiterator');
$prefetch->setPrefetch(2); //fetch 2 rows per query (for real world use this can be way higher)
$prefetch->setQuery($query);
// display the total number of documents found by solr
echo 'NumFound: ' . count($prefetch);
// show document IDs using the resultset iterator
foreach ($prefetch as $document) {
echo '<hr/>ID: '. $document->id;
}
htmlFooter();
```
\ No newline at end of file
This querytype accepts one or more documents as input and will return analysis details for each document.
Building an analysis document query
-----------------------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|-------------|---------|-------------------------------------------------|--------------------------------------|
| query | string | null | Query to use for query-time analysis |
| showmatch | boolean | null | |
| handler | string | analysis/document | |
| resultclass | string | Solarium\\QueryType\\Analysis\\Result\\Document | |
||
Executing an analysis document query
------------------------------------
Use the `analyze` method of the client to execute the query object. See the example code below.
Result of an analysis document query
------------------------------------
The result contains a nested data model that is best explained by looking at the example code below.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an analysis document query
$query = $client->createAnalysisDocument();
$query->setShowMatch(true);
$query->setQuery('ipod');
$doc = new Solarium\QueryType\Update\Query\Document(
array(
'id' => 'MA147LL',
'name' => 'Apple 60 GB iPod with Video Playback Black',
'manu' => 'Apple Computer Inc.',
'cat' => 'electronics',
'cat' => 'music',
'features' => 'iTunes, Podcasts, Audiobooks',
'features' => 'Stores up to 15,000 songs, 25,000 photos, or 150 hours of video',
'features' => '2.5-inch, 320x240 color TFT LCD display with LED backlight',
'features' => 'Up to 20 hours of battery life',
'features' => 'Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video',
'features' => 'Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, '.
'JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, '.
'Rechargeable capability, Battery level indication',
'includes' => 'earbud headphones, USB cable',
'weight' => 5.5,
'price' => 399.00,
'popularity' => 10,
'inStock' => true,
)
);
$query->addDocument($doc);
// this executes the query and returns the result
$result = $client->analyze($query);
// show the results
foreach ($result as $document) {
echo '<hr><h2>Document: ' . $document->getName() . '</h2>';
foreach ($document as $field) {
echo '<h3>Field: ' . $field->getName() . '</h3>';
$indexAnalysis = $field->getIndexAnalysis();
if (!empty($indexAnalysis)) {
echo '<h4>Index Analysis</h4>';
foreach ($indexAnalysis as $classes) {
echo '<h5>'.$classes->getName().'</h5>';
foreach ($classes as $result) {
echo 'Text: ' . $result->getText() . '<br/>';
echo 'Raw text: ' . $result->getRawText() . '<br/>';
echo 'Start: ' . $result->getStart() . '<br/>';
echo 'End: ' . $result->getEnd() . '<br/>';
echo 'Position: ' . $result->getPosition() . '<br/>';
echo 'Position history: ' . implode(', ', $result->getPositionHistory()) . '<br/>';
echo 'Type: ' . htmlspecialchars($result->getType()) . '<br/>';
echo 'Match: ' . var_export($result->getMatch(), true) . '<br/>';
echo '-----------<br/>';
}
}
}
$queryAnalysis = $field->getQueryAnalysis();
if (!empty($queryAnalysis)) {
echo '<h4>Query Analysis</h4>';
foreach ($queryAnalysis as $classes) {
echo '<h5>'.$classes->getName().'</h5>';
foreach ($classes as $result) {
echo 'Text: ' . $result->getText() . '<br/>';
echo 'Raw text: ' . $result->getRawText() . '<br/>';
echo 'Start: ' . $result->getStart() . '<br/>';
echo 'End: ' . $result->getEnd() . '<br/>';
echo 'Position: ' . $result->getPosition() . '<br/>';
echo 'Position history: ' . implode(', ', $result->getPositionHistory()) . '<br/>';
echo 'Type: ' . htmlspecialchars($result->getType()) . '<br/>';
echo 'Match: ' . var_export($result->getMatch(), true) . '<br/>';
echo '-----------<br/>';
}
}
}
}
}
htmlFooter();
```
This querytype accepts one or more values that can be analyzed for fieldtypes and/or fieldnames.
Building an analysis query
--------------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|-------------|---------|----------------------------------------------|--------------------------------------|
| query | string | null | Query to use for query-time analysis |
| showmatch | boolean | null | |
| handler | string | analysis/field | |
| resultclass | string | Solarium\\QueryType\\Analysis\\Result\\Field | |
| fieldvalue | string | | Value(s) to analyze |
| fieldname | string | | Fieldname(s) to analyze for |
| fieldtype | string | | Fieldtype(s) to analyze for |
||
Executing an analysis fieldquery
--------------------------------
Use the `analyze` method of the client to execute the query object. See the example code below.
Result of an analysis field query
---------------------------------
The result contains a nested data model that is best explained by looking at the example code below.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an analysis document query
$query = $client->createAnalysisField();
$query->setShowMatch(true);
$query->setFieldName('cat,title');
$query->setFieldType('text_general');
$query->setFieldValue('Apple 60 GB iPod with Video Playback Black');
$query->setQuery('ipod');
// this executes the query and returns the result
$results = $client->analyze($query);
// show the results
foreach ($results as $result) {
echo '<hr><h2>Result list: ' . $result->getName() . '</h2>';
foreach ($result as $item) {
echo '<h3>Item: ' . $item->getName() . '</h3>';
$indexAnalysis = $item->getIndexAnalysis();
if (!empty($indexAnalysis)) {
echo '<h4>Index Analysis</h4>';
foreach ($indexAnalysis as $classes) {
echo '<h5>'.$classes->getName().'</h5>';
foreach ($classes as $result) {
echo 'Text: ' . $result->getText() . '<br/>';
echo 'Raw text: ' . $result->getRawText() . '<br/>';
echo 'Start: ' . $result->getStart() . '<br/>';
echo 'End: ' . $result->getEnd() . '<br/>';
echo 'Position: ' . $result->getPosition() . '<br/>';
echo 'Position history: ' . implode(', ', $result->getPositionHistory()) . '<br/>';
echo 'Type: ' . htmlspecialchars($result->getType()) . '<br/>';
echo 'Match: ' . var_export($result->getMatch(), true) . '<br/>';
echo '-----------<br/>';
}
}
}
$queryAnalysis = $item->getQueryAnalysis();
if (!empty($queryAnalysis)) {
echo '<h4>Query Analysis</h4>';
foreach ($queryAnalysis as $classes) {
echo '<h5>'.$classes->getName().'</h5>';
foreach ($classes as $result) {
echo 'Text: ' . $result->getText() . '<br/>';
echo 'Raw text: ' . $result->getRawText() . '<br/>';
echo 'Start: ' . $result->getStart() . '<br/>';
echo 'End: ' . $result->getEnd() . '<br/>';
echo 'Position: ' . $result->getPosition() . '<br/>';
echo 'Position history: ' . implode(', ', $result->getPositionHistory()) . '<br/>';
echo 'Type: ' . htmlspecialchars($result->getType()) . '<br/>';
echo 'Match: ' . var_export($result->getMatch(), true) . '<br/>';
echo '-----------<br/>';
}
}
}
}
}
htmlFooter();
```
A analysis query is can be used to see how documents and/or fields are analysed step-by-step. Both at search and at index time. This way you see in detail how your Solr schema is effecting the indexing and searching of data.
There are two types of analysis:
- by document(s)
- by field(s) (fieldType or fieldName)
Both types are described in detail in the following sections.
An extract query can be used to index files in Solr. For more info see <http://wiki.apache.org/solr/ExtractingRequestHandler>
Building an extract query
-------------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|---------------|---------|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| handler | string | select | Name of the Solr request handler to use, without leading or trailing slashes |
| resultclass | string | Solarium\_Result\_Select | Classname for result. If you set a custom classname make sure the class is readily available (or through autoloading) |
| documentclass | string | Solarium\_Document\_ReadWrite | Classname for documents in the resultset. If you set a custom classname make sure the class is readily available (or through autoloading) |
| omitheader | boolean | true | Disable Solr headers (saves some overhead, as the values aren't actually used in most cases) |
||
Executing an Extract query
--------------------------
First of all create an Extract query instance and set the options, a file and document. Use the `extract` method of the client to execute the query object.
See the example code below.
Result of an extract query
--------------------------
The result of an extract query is similar to an update query,
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an extract query instance and add settings
$query = $client->createExtract();
$query->addFieldMapping('content', 'text');
$query->setUprefix('attr_');
$query->setFile(__DIR__.'/index.html');
$query->setCommit(true);
$query->setOmitHeader(false);
// add document
$doc = $query->createDocument();
$doc->id = 'extract-test';
$doc->some = 'more fields';
$query->setDocument($doc);
// this executes the query and returns the result
$result = $client->extract($query);
echo '<b>Extract query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
A MoreLikeThis (MLT) query is designed to generate information about "similar" documents using the MoreLikeThis functionality provided by Lucene. It supports faceting, paging, and filtering using CommonQueryParameters.
This query uses the [Solr MoreLikeThis Handler](http://wiki.apache.org/solr/MoreLikeThisHandler) that specifically returns MLT results. Alternatively you can use the [MLT component](V2:MoreLikeThis_component "wikilink") for the select query.
Building a MLT query
--------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|--------------------------|---------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| handler | string | select | Name of the Solr request handler to use, without leading or trailing slashes |
| resultclass | string | Solarium\_Result\_Select | Classname for result. If you set a custom classname make sure the class is readily available (or through autoloading) |
| documentclass | string | Solarium\_Document\_ReadWrite | Classname for documents in the resultset. If you set a custom classname make sure the class is readily available (or through autoloading) |
| query | string | \*:\* | Query to execute |
| start | int | 0 | Start position (offset) in the complete Solr query resultset, to paginate big resultsets. |
| rows | integer | 10 | Number of rows to fetch, starting from the 'start' (offset) position. It's a limit, you might get less. |
| fields | string | - ,score | Comma separated list of fields to fetch from Solr. There are two special values: '\*' meaning 'all fields' and 'score' to also fetch the Solr document score value. |
| sort | array | empty array | Array with sort field as key and sort order as values. Multiple entries possible, they are used in the order of the array. Example: array('price' =&gt; 'asc') |
| stream | boolean | false | Set to true to post query content instead of using the URL param |
| interestingTerms | string | none | Must be one of: none, list, details |
| matchinclude | boolean | false | |
| mltfields | string | none | The fields to use for similarity. NOTE: if possible, these should have a stored TermVector |
| minimumtermfrequency | int | none | |
| minimumdocumentfrequency | int | none | |
| minimumwordlength | int | none | |
| maximumwordlength | int | none | |
| maximumqueryterms | int | none | |
| maximumnumberoftokens | int | none | |
| boost | boolean | none | If true the query will be boosted by the interesting term relevance |
| queryfields | string | none | Query fields and their boosts using the same format as that used in DisMaxQParserPlugin. These fields must also be specified in fields. |
||
Executing a MLT query
---------------------
Use the `moreLikeThis` method of the client to execute the query object. See the example code below.
Result of a MLT query
---------------------
The result of a mlt query shares the features of the select query result. On top of that the following is added:
### Interestingterms
This will show what "interesting" terms are used for the MoreLikeThis query.
### Match
Get matched documents. Only available if matchinclude was set to true in the query.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
use Solarium\Client;
htmlHeader();
// create a client instance
$client = new Client($config);
// get a morelikethis query instance
$query = $client->createMoreLikeThis();
$query->setQuery('id:SP2514N');
$query->setMltFields('manu,cat');
$query->setMinimumDocumentFrequency(1);
$query->setMinimumTermFrequency(1);
$query->createFilterQuery('stock')->setQuery('inStock:true');
$query->setInterestingTerms('details');
$query->setMatchInclude(true);
// this executes the query and returns the result
$resultset = $client->select($query);
echo 'Document used for matching:<br/><table>';
foreach ($resultset->getMatch() as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table><hr/>';
// display the total number of MLT documents found by solr
echo 'Number of MLT matches found: '.$resultset->getNumFound().'<br/><br/>';
echo '<b>Listing of matched docs:</b>';
// show MLT documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
A ping query can be used to check the connection to the Solr server and the health of the Solr server. It's not just a network ping, it will execute a query to check Solr health. You can set this query in the Solr config with the 'pingQuery' directive.
*It's not advisable to check Solr with a ping before every request, this can have a big performance impact. You are better of using the ping query with intervals, or as a check after a query error to see if the query was faulty or if Solr has problems.*
To use ping queries first of all you need to have a ping query defined in your solrconfig.xml file and working. See the Solr wiki for more info about this: <http://wiki.apache.org/solr/SolrConfigXml#The_Admin.2BAC8-GUI_Section>
Creating a ping query
---------------------
You create a ping query using the createPing method of your client instance. This is a very simple query with only one option, the handler.
**Available options:**
| Name | Type | Default value | Description |
|---------|--------|---------------|------------------------------------------------|
| handler | string | admin/ping | Path to the ping handler as configured in Solr |
||
Executing a ping query
----------------------
Use the `ping` method of the client to execute the query object. See the example code below.
Result of a ping query
----------------------
The result of a ping query is just as simple as the ping query itself: it either works or not. There is no useful result data. In case of error an exception will be thrown.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// check solarium version available
echo 'Solarium library version: ' . Solarium\Client::VERSION . ' - ';
// create a client instance
$client = new Solarium\Client($config);
// create a ping query
$ping = $client->createPing();
// execute the ping query
try {
$result = $client->ping($ping);
echo 'Ping query successful';
echo '<br/><pre>';
var_dump($result->getData());
echo '</pre>';
} catch (Solarium\Exception $e) {
echo 'Ping query failed';
}
htmlFooter();
```
The helper offers two types of escaping: term and phrase. Term escaping will escape more characters than phrase escaping. Use phrase escaping when you want to escape a whole phrase and treat is a search string. It will be enclosed in quotes so any special characters lose their meaning and also the search will be done on the whole string as a single phrase. In all other cases use term escaping.
An example of term escaping in use for a query that would fail without escaping:
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// search input string, this value fails without escaping because of the double-quote
$input = 'ATA "133';
// in this case phrase escaping is used (most common) but you can also do term escaping, see the manual
// also note that the same can be done using the placeholder syntax, see example 6.3
$helper = $query->getHelper();
$query->setQuery('features:' . $helper->escapePhrase($input));
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
The query helper also includes support for geospatial query functions / filters. It can be hard to remember the exact syntax, in that case you can use the helper API to generate the syntax for you. You still need to place the result of the helper into a querystring yourself.
The following methods are available:
- geofilt($field, $pointX, $pointY, $distance)
- bbox($field, $pointX, $pointY, $distance)
- geodist($field, $pointX, $pointY)
The query helper has an 'assemble' method that can be used for building query strings in a way that is somewhat similar to SQL prepared statements. The placeholder syntax will be used via the built-in support in various (query) classes in most cases, but they all map to the same 'assemble' method of the query helper.
This method supports the following placeholder syntax:
| Placeholder | Description |
|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| %1% | This means: replace with the literal contents of the first entry of the supplied array of bind vars |
| %L3% | Replace with the literal contents of the third entry of the supplied array of bind vars. This is the default, so if you don't supply a 'mode' like in the first example literal will be used. |
| %P2% | Replace with the contents of the second bind var entry, escaping as a phrase |
| %T1% | Replace with the contents of the second bind var entry, escaping as a term |
||
Some notes:
- The bind vars are supplied as an array. The placeholder number refers to the position of the entry in the array, not the array key! Position 1 is actually array key 0.
- You can use the same bind var multiple times, even with different modes (literal, phrase or term)
- Placeholder and bind var order don't need to match, just refer to the right positions.
- The letters for the modes L (Literal), P (Phrase) and T (Term) are not case-sensitive.
Support in classes
------------------
Currently the following classes have built-in support for the placeholder syntax, making it even easier to use because you don't even need to call the query helper yourself:
- Select query method setQuery($query, $bind = null)
- Facet Query method setQuery($query, $bind = null)
- FilterQuery method setQuery($query, $bind = null)
- Spellcheck component methode setQuery($query, $bind = null)
In all other cases you can always use the 'assemble' method of the query helper and use the result as a normal query string.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// search input string, this value fails without escaping because of the double-quote
$input = 'ATA "133';
// the placeholder syntax applies phrase escaping to the first term
// see the manual for all supported formats
$query->setQuery('features: %p1% AND inStock:%2%', array($input, 1));
// show the result after replacing the placeholders with values
echo $query->getQuery() . '<br/>';
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
As you could probably already guess by the name, the query helper class is there to help you create query strings. It offers various methods to simplify the complex parts of a query string into an easy to use API. This includes term/phrase escaping, range queries and (geospatial) functions.
You can get a query helper instance by calling the 'getHelper()' method of your query instance. This is available in all query classes.
Two special types of helper methods are
Helper methods for general use
------------------------------
- rangeQuery($field, $from, $to, $inclusive = true)
- qparser($name, $params = array())
- functionCall($name, $params = array())
- join($from, $to, $dereferenced = false)
- formatDate($input)
- cacheControl($useCache, $cost)
- qparserTerm($field, $weight)
See the API docs (linked at the bottom of this page) for more details.
Dereferenced params
-------------------
The query helper also supports dereferenced params. See the implementation of the join() and qparser() methods. For more info also see <http://wiki.apache.org/solr/LocalParams>: Parameter dereferencing or indirection allows one to use the value of another argument rather than specifying it directly. This can be used to simplify queries, decouple user input from query parameters, or decouple front-end GUI parameters from defaults set in solrconfig.xml.
Special helper methods
----------------------
See the next pages for more info about escaping, placeholders and geospatial helpers.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance and a query helper instance
$query = $client->createSelect();
$helper = $query->getHelper();
// add a filterquery on a price range, using the helper to generate the range
$query->createFilterQuery('price')->setQuery($helper->rangeQuery('price', 10, 300));
// add a filterquery to find products in a range of 5km, using the helper to generate the 'geofilt' filter
$query->createFilterQuery('region')->setQuery($helper->geofilt(45.15, -93.85, 'store', 5));
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
A RealtimeGet query is useful when using Solr as a NoSql store. For more info see <http://wiki.apache.org/solr/RealTimeGet>
Building a realtime query
-------------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|---------------|--------|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| handler | string | select | Name of the Solr request handler to use, without leading or trailing slashes |
| resultclass | string | Solarium\_Result\_Select | Classname for result. If you set a custom classname make sure the class is readily available (or through autoloading) |
| documentclass | string | Solarium\_Document\_ReadWrite | Classname for documents in the resultset. If you set a custom classname make sure the class is readily available (or through autoloading) |
||
Executing a RealtimeGet query
-----------------------------
First of all create a RealtimeGet query instance and set one ore multiple IDs. Use the `realtimeGet` method of the client to execute the query object.
See the example code below.
Result of a RealtimeGet query
-----------------------------
The result of a RealtimeGet query is similar to a select query,
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// create a new document
$id = time();
$doc1 = $update->createDocument();
$doc1->id = $id;
$doc1->name = 'realtime-get-test-'.date('Y-m-d H:i:s');
// set a very long commitWithin time and add it to solr
$update->addDocument($doc1, null, 1000000);
$client->update($update);
// try to get the document using a normal select, this should return 0 results
$query = $client->createSelect();
$query->setQuery('id:%1%', array($id));
$resultset = $client->select($query);
echo 'NumFound with standard select: '.$resultset->getNumFound().'<br/>';
// now with realtime get, this should return 1 result
$query = $client->createRealtimeGet();
$query->addId($id);
$result = $client->realtimeGet($query);
echo 'NumFound with realtime get: '.$result->getNumFound().'<br/>';
// Display the document
echo '<hr/><table>';
foreach ($result->getDocument() as $field => $value) {
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
htmlFooter();
```
A filterquery can be used to restrict the set of documents for your query, without affecting score. They also have the benefit of being cached separately by Solr, so reusing filterqueries is very efficient.
Options
-------
The options below can be set as query option values, but also by using the set/get methods. See the API docs for all available methods.
| Name | Type | Default value | Description |
|-------|----------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| key | string | null | This value is used as the key for the filterquery in the select query object. Kind of a unique-id for filterqueries. |
| tag | string / array | empty array | Tags for excluding filterqueries in facets. A single filterquery may have multiple tags and a single tag may be used for multiple filterqueries. |
| query | string | null | The query to use as filter on the set of documents. |
||
Examples
--------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// create a filterquery
$query->createFilterQuery('maxprice')->setQuery('price:[1 TO 300]');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
A select query has options and commands. These commands and options are instructions for the client classes to build and execute a request and return the correct result. In the following sections both the options and commands will be discussed in detail.
Options
-------
The options below can be set as query option values, but also by using the set/get methods. See the API docs for all available methods.
| Name | Type | Default value | Description |
|----------------------|------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| handler | string | select | Name of the Solr request handler to use, without leading or trailing slashes |
| resultclass | string | Solarium\_Result\_Select | Classname for result. If you set a custom classname make sure the class is readily available (or through autoloading) |
| documentclass | string | Solarium\_Document\_ReadWrite | Classname for documents in the resultset. If you set a custom classname make sure the class is readily available (or through autoloading) |
| query | string | \*:\* | Query to execute |
| start | int | 0 | Start position (offset) in the complete Solr query resultset, to paginate big resultsets. |
| rows | integer | 10 | Number of rows to fetch, starting from the 'start' (offset) position. It's a limit, you might get less. |
| fields | string | - ,score | Comma separated list of fields to fetch from Solr. There are two special values: '\*' meaning 'all fields' and 'score' to also fetch the Solr document score value. |
| sort | array | empty array | Array with sort field as key and sort order as values. Multiple entries possible, they are used in the order of the array. Example: array('price' =&gt; 'asc') |
| querydefaultoperator | string | null | With a null value the default of your Solr config will be used. If you want to override this supply 'AND' or 'OR' as the value. |
| querydefaultfield | string | null | With a null value the default of your Solr config will be used. If you want to override this supply a field name as the value. |
| responsewriter | string | json | You can set this to 'phps' for improved response parsing performance, at the cost of a (possible) security risk. Only use 'phps' for trusted Solr instances. |
| tag | array of strings | null | You can supply one or multiple tags for the main query string, to allow for exclusion of the main query in facets |
||
Examples
--------
A simple select with some params, using the API mode:
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// set a query (all prices starting from 12)
$query->setQuery('price:[12 TO *]');
// set start and rows param (comparable to SQL limit) using fluent interface
$query->setStart(2)->setRows(20);
// set fields to fetch (this overrides the default setting 'all fields')
$query->setFields(array('id','name','price', 'score'));
// sort the results by price ascending
$query->addSort('price', $query::SORT_ASC);
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display the max score
echo '<br>MaxScore: '.$resultset->getMaxScore();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
An example using the select query in config mode: (filterqueries and components will be explained in following sections)
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// In this case an array is used for configuration to keep the example simple.
// For an easier to use config file you are probably better of with another format, like Zend_Config_Ini
// See the documentation for more info about this.
$select = array(
'query' => '*:*',
'start' => 2,
'rows' => 20,
'fields' => array('id','name','price'),
'sort' => array('price' => 'asc'),
'filterquery' => array(
'maxprice' => array(
'query' => 'price:[1 TO 300]'
),
),
'component' => array(
'facetset' => array(
'facet' => array(
// notice this config uses an inline key value, instead of array key like the filterquery
array('type' => 'field', 'key' => 'stock', 'field' => 'inStock'),
)
),
),
);
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance based on the config
$query = $client->createSelect($select);
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
There are so many options available for use in a Solr select query that putting them all in a single model would result in a hard to maintain, hard to use API and decreased performance. Therefore the select query model itself only implements common query parameters. Additional functionality can be added by using components.
Components have multiple advantages:
- they model specific Solr components/handlers in detail, in some cases with sub-models
- components are only loaded when actually used
- the component structure allows for easy addition of extra (custom) components
The Solarium concept of a 'component' is not exactly the same as a Solr component. For instance, the Solr FacetComponent is reflected in Solarium by a FacetSet component. And Solariums DisMax component actually uses the DisMaxQParserPlugin of Solr. Because there are so many types of components, parsers, handlers etcetera in Solr this is simplified into just 'components' in Solarium. For each Solarium component you can find what part of Solr it uses in the docs.
For a description of Solr debugging see the [http://wiki.apache.org/solr/CommonQueryParameters\#Debugging Solr wiki page](http://wiki.apache.org/solr/CommonQueryParameters#Debugging_Solr_wiki_page "wikilink").
Options
-------
| Name | Type | Default value | Description |
|--------------|--------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| explainother | string | null | Using this parameter you can specify a Lucene query to identify a set of documents. If non-blank, the explain info of each document that matches this query, relative to the main query (specified by the q parameter) will be returned along with the rest of the debugging information. |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setQuery('ipod');
// add debug settings
$debug = $query->getDebug();
$debug->setExplainOther('id:MA*');
// this executes the query and returns the result
$resultset = $client->select($query);
$debugResult = $resultset->getDebug();
// display the debug results
echo '<h1>Debug data</h1>';
echo 'Querystring: ' . $debugResult->getQueryString() . '<br/>';
echo 'Parsed query: ' . $debugResult->getParsedQuery() . '<br/>';
echo 'Query parser: ' . $debugResult->getQueryParser() . '<br/>';
echo 'Other query: ' . $debugResult->getOtherQuery() . '<br/>';
echo '<h2>Explain data</h2>';
foreach ($debugResult->getExplain() as $key => $explanation) {
echo '<h3>Document key: ' . $key . '</h3>';
echo 'Value: ' . $explanation->getValue() . '<br/>';
echo 'Match: ' . (($explanation->getMatch() == true) ? 'true' : 'false') . '<br/>';
echo 'Description: ' . $explanation->getDescription() . '<br/>';
echo '<h4>Details</h4>';
foreach ($explanation as $detail) {
echo 'Value: ' . $detail->getValue() . '<br/>';
echo 'Match: ' . (($detail->getMatch() == true) ? 'true' : 'false') . '<br/>';
echo 'Description: ' . $detail->getDescription() . '<br/>';
echo '<hr/>';
}
}
echo '<h2>ExplainOther data</h2>';
foreach ($debugResult->getExplainOther() as $key => $explanation) {
echo '<h3>Document key: ' . $key . '</h3>';
echo 'Value: ' . $explanation->getValue() . '<br/>';
echo 'Match: ' . (($explanation->getMatch() == true) ? 'true' : 'false') . '<br/>';
echo 'Description: ' . $explanation->getDescription() . '<br/>';
echo '<h4>Details</h4>';
foreach ($explanation as $detail) {
echo 'Value: ' . $detail->getValue() . '<br/>';
echo 'Match: ' . (($detail->getMatch() == true) ? 'true' : 'false') . '<br/>';
echo 'Description: ' . $detail->getDescription() . '<br/>';
echo '<hr/>';
}
}
echo '<h2>Timings (in ms)</h2>';
echo 'Total time: ' . $debugResult->getTiming()->getTime() . '<br/>';
echo '<h3>Phases</h3>';
foreach ($debugResult->getTiming()->getPhases() as $phaseName => $phaseData) {
echo '<h4>' . $phaseName . '</h4>';
foreach ($phaseData as $class => $time) {
echo $class . ': ' . $time . '<br/>';
}
echo '<hr/>';
}
htmlFooter();
```
The DisMax component can be used if you want to search using the DisMaxRequestHandler. This also affects the handling of the query string of the select query object (the 'main' query).
Options
-------
| Name | Type | Default value | Description |
|------------------|--------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| queryalternative | string | null | If specified, this query will be used (and parsed by default using standard query parsing syntax) when the main query string is not specified or blank. |
| queryfields | string | null | List of fields and the "boosts" to associate with each of them when building DisjunctionMaxQueries from the user's query. The format supported is "fieldOne^2.3 fieldTwo fieldThree^0.4" |
| mimimummatch | string | null | This option makes it possible to say that a certain minimum number of clauses must match. See Solr manual for details. |
| phrasefields | string | null | This param can be used to "boost" the score of documents in cases where all of the terms in the "q" param appear in close proximity. Format is: "fieldA^1.0 fieldB^2.2" |
| phraseslop | string | null | Amount of slop on phrase queries built for "pf" fields (affects boosting) |
| queryphraseslop | string | null | Amount of slop on phrase queries explicitly included in the user's query string (in qf fields; affects matching) |
| tie | float | null | Float value to use as tiebreaker in DisjunctionMaxQueries |
| boostquery | string | null | A raw query string (in the SolrQuerySyntax) that will be included with the user's query to influence the score. |
| boostfunctions | string | null | Functions (with optional boosts) that will be included in the user's query to influence the score. Format is: "funcA(arg1,arg2)^1.2 funcB(arg3,arg4)^2.2" |
||
### Selecting all documents
The normal Solr syntax \*:\* doesn't work for Dismax. To select all documents you need to do two things:
- make sure the 'query' value of the select query is set to an empty string. **The default query value in a Solarium select query is \*:\* so you need manually set it to an empty string!**
- set the dismax query alternative to \*:\*. While the DisMax 'main' query doesn't support the normal query syntax, the query alternative does.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the dismax component and set a boost query
$dismax = $query->getDisMax();
$dismax->setBoostQuery('cat:"graphics card"^2');
// this query is now a dismax query
$query->setQuery('memory -printer');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
Edismax
-------
For eDismax you should use the separate eDisMax component.
For a description of Solr distributed search (also referred to as 'shards' or 'sharding') see the [http://wiki.apache.org/solr/DistributedSearch\#Distributed\_Search\_Example Solr wiki page](http://wiki.apache.org/solr/DistributedSearch#Distributed_Search_Example_Solr_wiki_page "wikilink").
Options
-------
| Name | Type | Default value | Description |
|--------------|--------|---------------|----------------------------------------------------------------------------|
| shards | string | null | Shards to use for request |
| shardhandler | string | null | Request handler to use |
| collections | string | null | A list of collections, for use with SolrCloud (available in Solarium 3.1+) |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// add distributed search settings
// see http://wiki.apache.org/solr/DistributedSearch#Distributed_Search_Example for setting up two solr instances
$distributedSearch = $query->getDistributedSearch();
$distributedSearch->addShard('shard1', 'localhost:8983/solr');
$distributedSearch->addShard('shard2', 'localhost:7574/solr');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
eDisMax is a Solr component that adds features to the 'standard' DisMax component. As the params are not compatible between the two Solarium also has a dedicated eDisMax component. It has many similarities to the DisMax component, in the library it event extends the Dismax class.
Options
-------
The eDismax component supports the options of the dismax component and adds the following options:
| Name | Type | Default value | Description |
|---------------------|--------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| boostfunctionsmult | string | null | Functions (with optional boosts) that will be included in the user's query to influence the score by multiplying its value. Format is: "funcA(arg1,arg2)^1.2 funcB(arg3,arg4)^2.2" |
| phrasebigramfields | string | null | As with 'pf' but chops the input into bi-grams, e.g. "the brown fox jumped" is queried as "the brown" "brown fox" "fox jumped". Format is: "fieldA^1.0 fieldB^2.2 fieldC^3.5" |
| phrasebigramslop | string | null | As with 'ps' but sets default slop factor for 'pf2'. If not specified, 'ps' will be used. |
| phrasetrigramfields | string | null | As with 'pf' but chops the input into tri-grams, e.g. "the brown fox jumped" is queried as "the brown fox" "brown fox jumped". Format is: "fieldA^1.0 fieldB^2.2 fieldC^3.5" |
| phrasetrigramslop | string | null | As with 'ps' but sets default slop factor for 'pf3'. If not specified, 'ps' will be used. |
| userfields | string | null | Specifies which schema fields the end user shall be allowed to query for explicitly. This parameter supports wildcards. |
||
### Selecting all documents
The normal Solr syntax \*:\* doesn't work for Dismax. To select all documents you need to do two things:
- make sure the 'query' value of the select query is set to an empty string. **The default query value in a Solarium select query is \*:\* so you need manually set it to an empty string!**
- set the dismax query alternative to \*:\*. While the DisMax 'main' query doesn't support the normal query syntax, the query alternative does.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the dismax component and set a boost query
$edismax = $query->getEDisMax();
// this query is now a dismax query
$query->setQuery('memory -printer');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
This facet type allows you to count the number of occurences of a term in a specific field.
Options
-------
The options below can be set as query option values, but also by using the set/get methods. See the API docs for all available methods.
Only the facet-type specific options are listed. See [Facetset component](V3:Facetset_component "wikilink") for the option shared by all facet types.
| Name | Type | Default value | Description |
|----------|---------|---------------|----------------------------------------------------------------------------------------------------------------------------|
| field | string | null | The index field for the facet. |
| sort | string | null | Sort order (sorted by count). Use one of the class constants. |
| limit | int | null | Limit the facet counts |
| offset | int | null | Show facet count starting from this offset |
| mincount | int | null | Minimal term count to be included in facet count results. |
| missing | boolean | null | Also make a count of all document that have no value for the facet field. |
| method | string | null | Use one of the class constants as value. See <http://wiki.apache.org/solr/SimpleFacetParameters#facet.method> for details. |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet field instance and set options
$facetSet->createFacetField('stock')->setField('inStock');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
This facet type is a combination of multiple facet queries into a single facet, not a standard Solr facet type. It was added because it is quite common to present multiple query counts as a single facet. In that case this multiquery facet is much easier to work with than multiple separate facet queries.
Internally this facet uses multiple instances of the [Facet query](V3:Facet_query "wikilink") class. You can use the 'createQuery' method to add new facet queries.
You can also manage the excludes for a multiquery facet by calling 'addExclude', 'removeExclude' and 'clearExcludes'. Changes to excludes will be forwarded to all facet queries.
See the API docs for all available methods.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet query instance and set options
$facet = $facetSet->createFacetMultiQuery('stock');
$facet->createQuery('stock_pricecat1', 'inStock:true AND price:[1 TO 300]');
$facet->createQuery('nostock_pricecat1', 'inStock:false AND price:[1 TO 300]');
$facet->createQuery('stock_pricecat2', 'inStock:true AND price:[300 TO *]');
$facet->createQuery('nostock_pricecat2', 'inStock:false AND price:[300 TO *]');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Multiquery facet counts:<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $key => $count) {
echo $key . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
The facet class supports the Solr pivot facet: <http://wiki.apache.org/solr/SimpleFacetParameters#Pivot_.28ie_Decision_Tree.29_Faceting>
Options
-------
The options below can be set as query option values, but also by using the set/get methods. See the API docs for all available methods.
Only the facet-type specific options are listed. See [Facetset component](V3:Facetset_component "wikilink") for the option shared by all facet types.
| Name | Type | Default value | Description |
|----------|--------|---------------|------------------------------------------|
| mincount | int | null | Facet results limited by a minimum count |
| fields | string | null | Field to pivot on, separated by commas |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create two facet pivot instances
$facet = $facetSet->createFacetPivot('cat-popularity-instock');
$facet->addFields('cat,popularity,inStock');
$facet->setMinCount(0);
$facet = $facetSet->createFacetPivot('popularity-cat');
$facet->addFields('popularity,cat');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet results
$facetResult = $resultset->getFacetSet()->getFacet('cat-popularity-instock');
echo '<h3>cat &raquo; popularity &raquo; instock</h3>';
foreach ($facetResult as $pivot) {
displayPivotFacet($pivot);
}
$facetResult = $resultset->getFacetSet()->getFacet('popularity-cat');
echo '<h3>popularity &raquo; cat</h3>';
foreach ($facetResult as $pivot) {
displayPivotFacet($pivot);
}
htmlFooter();
/**
* Recursively render pivot facets
*
* @param $pivot
*/
function displayPivotFacet($pivot)
{
echo '<ul>';
echo '<li>Field: '.$pivot->getField().'</li>';
echo '<li>Value: '.$pivot->getValue().'</li>';
echo '<li>Count: '.$pivot->getCount().'</li>';
foreach ($pivot->getPivot() as $nextPivot) {
displayPivotFacet($nextPivot);
}
echo '</ul>';
}
```
This facet type allows you to supply an arbitrary query (normal query syntax) to count the number of results of. This query is not affected by the 'main' query. Filterqueries do affect this count, but they can be excluded.
Options
-------
The options below can be set as query option values, but also by using the set/get methods. See the API docs for all available methods.
Only the facet-type specific options are listed. See [Facetset component](V3:Facetset_component "wikilink") for the option shared by all facet types.
| Name | Type | Default value | Description |
|-------|--------|---------------|---------------------------------|
| query | string | \*:\* | The query to use for the count. |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet query instance and set options
$facetSet->createFacetQuery('stock')->setQuery('inStock: true');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet query count
$count = $resultset->getFacetSet()->getFacet('stock')->getValue();
echo '<hr/>Facet query count : ' . $count;
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
The facet class supports the Solr range facet: <http://wiki.apache.org/solr/SimpleFacetParameters#Facet_by_Range>
Options
-------
The options below can be set as query option values, but also by using the set/get methods. See the API docs for all available methods.
Only the facet-type specific options are listed. See [Facetset component](V3:Facetset_component "wikilink") for the option shared by all facet types.
| Name | Type | Default value | Description |
|---------|--------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
| field | string | null | This param indicates what field to create range facets for |
| start | string | null | The lower bound of the ranges. |
| end | string | null | The upper bound of the ranges. |
| gap | string | null | The size of each range expressed as a value to be added to the lower bound. |
| hardend | string | null | A Boolean parameter instructing Solr what to do in the event that facet.range.gap does not divide evenly between facet.range.start and facet.range.end. |
| other | string | null | This param indicates what to count in addition to the counts for each range constraint between facet.range.start and facet.range.en |
| include | string | null | Specify count bounds |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet field instance and set options
$facet = $facetSet->createFacetRange('priceranges');
$facet->setField('price');
$facet->setStart(1);
$facet->setGap(100);
$facet->setEnd(1000);
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet ranges:<br/>';
$facet = $resultset->getFacetSet()->getFacet('priceranges');
foreach ($facet as $range => $count) {
echo $range . ' to ' . ($range + 100) . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
The concept of a 'facetset' is doesn't exist in Solr. It was added to Solarium to have one central component for using facets of various type. You can use the facetset to create and manage facets, and also to set global facet options.
See the API docs for all methods. In the following sections facet types will be detailed. The examples used on those pages will also show the usage of the facetset component.
Global facet options
--------------------
| Name | Type | Default value | Description |
|----------|---------|---------------|------------------------------------------|
| prefix | string | null | Limit the terms for faceting by a prefix |
| sort | string | null | Set the facet sort order |
| limit | int | null | Set the facet limit |
| mincount | int | null | Set the facet mincount |
| missing | boolean | null | Set the 'count missing' option |
||
Standard facet options
----------------------
All facet types available in the facetset extend a base class that offers a standard set of options. The following options are available for ALL facet types:
| Name | Type | Default value | Description |
|----------|--------|---------------|-------------------------------------------------------------|
| key | string | null | Key to identify the facet (mandatory) |
| excludes | string | null | Add one or multiple filterquery tags to exclude for a facet |
||
For a description of Solr grouping (also referred to as 'result grouping' or 'field collapse') see the [http://wiki.apache.org/solr/FieldCollapsing Solr wiki page](http://wiki.apache.org/solr/FieldCollapsing_Solr_wiki_page "wikilink").
It's important to have a good understanding of the available options, as they can have have big effects on the result format.
Options
-------
| Name | Type | Default value | Description |
|-----------------|---------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| queries | string | null | Queries to generate grouped results for. Separate multiple fields with commas. |
| fields | string | null | Fields to generate grouped results for. Separate multiple fields with commas. |
| limit | int | null | The number of results (documents) to return for each group |
| offset | int | null | The offset into the document list of each group |
| sort | string | null | How to sort documents within a single group |
| mainresult | boolean | null | If true, the result of the first field grouping command is used as the main resultset. This way you can handle the resultdata like a normal search result, instead of the grouping result format. |
| numberofgroups | boolean | null | If true, include a count of the number of groups that have matched the query |
| cachepercentage | int | null | If &gt; 0 enables grouping cache in Solr. See Solr docs for details. |
| truncate | boolean | null | If true, facet counts are based on the most relevant document of each group matching the query. This param is available since Solarium 3.3 and only works with Solr 3.4 and up. |
| function | string | null | Group based on the unique values of a function query. Only available in Solr 4.0+ |
| facet | boolean | null | Group based on the unique values of a function query. Only available in Solr 4.0+ |
| format | string | null | If 'simple', the grouped documents are presented in a single flat list. |
||
Examples
--------
Grouping by field: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setRows(50);
// get grouping component and set a field to group by
$groupComponent = $query->getGrouping();
$groupComponent->addField('inStock');
// maximum number of items per group
$groupComponent->setLimit(3);
// get a group count
$groupComponent->setNumberOfGroups(true);
// this executes the query and returns the result
$resultset = $client->select($query);
$groups = $resultset->getGrouping();
foreach ($groups as $groupKey => $fieldGroup) {
echo '<h1>'.$groupKey.'</h1>';
echo 'Matches: '.$fieldGroup->getMatches().'<br/>';
echo 'Number of groups: '.$fieldGroup->getNumberOfGroups();
foreach ($fieldGroup as $valueGroup) {
echo '<h2>'.(int)$valueGroup->getValue().'</h2>';
foreach ($valueGroup as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
}
}
htmlFooter();
```
Grouping by query: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get grouping component and create two query groups
$groupComponent = $query->getGrouping();
$groupComponent->addQuery('price:[0 TO 99.99]');
$groupComponent->addQuery('price:[100 TO *]');
// sorting inside groups
$groupComponent->setSort('price desc');
// maximum number of items per group
$groupComponent->setLimit(5);
// this executes the query and returns the result
$resultset = $client->select($query);
$groups = $resultset->getGrouping();
foreach ($groups as $groupKey => $group) {
echo '<h1>'.$groupKey.'</h1>';
foreach ($group as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
}
htmlFooter();
```
The highlighting component can be used to highlight matches in content. For more info see <http://wiki.apache.org/solr/HighlightingParameters>
Options
-------
| Name | Type | Default value | Description |
|--------------------------|---------|---------------|------------------------------------------------------------------------------------|
| fields | string | null | Fields to generate highlighted snippets for. Separate multiple fields with commas. |
| snippets | int | null | Maximum number of snippets per field |
| fragsize | int | null | The size, in characters, of fragments to consider for highlighting |
| mergecontiguous | boolean | null | Collapse contiguous fragments into a single fragment |
| requirefieldmatch | boolean | null | requireFieldMatch option |
| maxanalyzedchars | int | null | How many characters into a document to look for suitable snippets |
| alternatefield | string | null | Alternatefield option |
| maxalternatefieldlength | int | null | maxAlternateFieldLength option |
| formatter | string | null | formatter option |
| simpleprefix | string | null | Solr option h1.simple.pre |
| simplepostfix | string | null | Solr option h1.simple.post |
| fragmenter | string | null | |
| fraglistbuilder | string | null | |
| fragmentsbuilder | string | null | |
| usefastvectorhighlighter | boolean | null | |
| usephrasehighlighter | boolean | null | |
| highlightmultiterm | boolean | null | |
| regexslop | float | null | |
| regexpattern | string | null | |
| regexmaxanalyzedchars | int | null | |
| query | string | null | Overrides the q parameter for highlighting |
| phraselimit | int | null | |
| multivaluedseparatorchar | string | null | |
| boundaryscannerchars | string | null | |
| boundaryscannermaxscan | int | null | |
| boundaryscannertype | string | null | |
| boundaryscannercountry | string | null | |
||
Per-field settings
------------------
Several options can be overridden on a per-field basis. You can use the `getField` method to get a field options instance. See the example below.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setQuery('memory');
// get highlighting component and apply settings
$hl = $query->getHighlighting();
$hl->setFields('name, features');
$hl->setSimplePrefix('<b>');
$hl->setSimplePostfix('</b>');
// this executes the query and returns the result
$resultset = $client->select($query);
$highlighting = $resultset->getHighlighting();
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table><br/><b>Highlighting results:</b><br/>';
// highlighting results can be fetched by document id (the field defined as uniquekey in this schema)
$highlightedDoc = $highlighting->getResult($document->id);
if ($highlightedDoc) {
foreach ($highlightedDoc as $field => $highlight) {
echo implode(' (...) ', $highlight) . '<br/>';
}
}
}
htmlFooter();
```
Per-field settings:
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setQuery('memory');
// get highlighting component and apply settings
// highlights are applied to three fields with a different markup for each field
// much more per-field settings are available, see the manual for all options
$hl = $query->getHighlighting();
$hl->getField('name')->setSimplePrefix('<b>')->setSimplePostfix('</b>');
$hl->getField('cat')->setSimplePrefix('<u>')->setSimplePostfix('</u>');
$hl->getField('features')->setSimplePrefix('<i>')->setSimplePostfix('</i>');
// this executes the query and returns the result
$resultset = $client->select($query);
$highlighting = $resultset->getHighlighting();
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table><br/><b>Highlighting results:</b><br/>';
// highlighting results can be fetched by document id (the field defined as uniquekey in this schema)
$highlightedDoc = $highlighting->getResult($document->id);
if ($highlightedDoc) {
foreach ($highlightedDoc as $field => $highlight) {
echo implode(' (...) ', $highlight) . '<br/>';
}
}
}
htmlFooter();
```
The morelikethis component can be used if you want to retrieve similar documents for your query results. This component uses morelikethis in the standardrequesthandler, not the standalone morelikethis handler. For more info see <http://wiki.apache.org/solr/MoreLikeThis>
Options
-------
| Name | Type | Default value | Description |
|--------------------------|---------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| fields | string | null | The fields to use for similarity. NOTE: if possible, these should have a stored TermVector. Separate multiple fields with commas. |
| minimumtermfrequency | int | null | Minimum Term Frequency - the frequency below which terms will be ignored in the source doc. |
| mimimumdocumentfrequency | int | null | Minimum Document Frequency - the frequency at which words will be ignored which do not occur in at least this many docs. |
| minimumwordlength | int | null | Minimum word length below which words will be ignored. |
| maximumwordlength | int | null | Maximum word length above which words will be ignored. |
| maximumqueryterms | int | null | Maximum number of query terms that will be included in any generated query. |
| maximumnumberoftokens | int | null | Maximum number of tokens to parse in each example doc field that is not stored with TermVector support. |
| boost | boolean | null | If true the query will be boosted by the interesting term relevance. |
| queryfields | string | null | Query fields and their boosts using the same format as that used in DisMaxQParserPlugin. These fields must also be specified in fields.Separate multiple fields with commas. |
| count | int | null | The number of similar documents to return for each result |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// add a query and morelikethis settings (using fluent interface)
$query->setQuery('apache')
->getMoreLikeThis()
->setFields('manu,cat')
->setMinimumDocumentFrequency(1)
->setMinimumTermFrequency(1);
// this executes the query and returns the result
$resultset = $client->select($query);
$mlt = $resultset->getMoreLikeThis();
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table><br/><b>MLT results:</b><br/>';
// mlt results can be fetched by document id (the field defined as uniquekey in this schema)
$mltResult = $mlt->getResult($document->id);
if ($mltResult) {
echo 'Max score: '.$mltResult->getMaximumScore().'<br/>';
echo 'NumFound: '.$mltResult->getNumFound().'<br/>';
echo 'Num. fetched: '.count($mltResult).'<br/>';
foreach ($mltResult as $mltDoc) {
echo 'MLT result doc: '. $mltDoc->name . ' (id='. $mltDoc->id . ')<br/>';
}
} else {
echo 'No MLT results';
}
}
htmlFooter();
```
For a description of Solr spellcheck (also referred to as 'query suggest') see the [http://wiki.apache.org/solr/SpellCheckComponent Solr wiki page](http://wiki.apache.org/solr/SpellCheckComponent_Solr_wiki_page "wikilink").
The `setQuery()` method of this component supports [placeholders](V3:Placeholders "wikilink").
Options
-------
| Name | Type | Default value | Description |
|-------------------------|---------|---------------|----------------------------------------------------------------------------------------|
| query | string | null | Query to spellcheck |
| build | boolean | null | Build the spellcheck dictionary? |
| reload | boolean | null | Reload the dictionary? |
| dictionary | string | null | The name of the dictionary to use |
| count | int | null | The maximum number of suggestions to return |
| onlymorepopular | boolean | null | Only return suggestions that result in more hits for the query than the existing query |
| extendedresults | boolean | null | |
| collate | boolean | null | |
| maxcollations | int | null | |
| maxcollationtries | string | null | |
| maxcollationevaluations | int | null | |
| collateextendedresults | string | null | |
| accuracy | float | null | |
||
Collate params
--------------
Using the API method setCollateParam($param, $value) you can set any collate params you need. For more info please see this page: <http://wiki.apache.org/solr/SpellCheckComponent#spellcheck.collateParam.XX>
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setRows(0);
// add spellcheck settings
$spellcheck = $query->getSpellcheck();
$spellcheck->setQuery('tes');
$spellcheck->setCount(10);
$spellcheck->setBuild(true);
$spellcheck->setCollate(true);
$spellcheck->setExtendedResults(true);
$spellcheck->setCollateExtendedResults(true);
// this executes the query and returns the result
$resultset = $client->select($query);
$spellcheckResult = $resultset->getSpellcheck();
echo '<h1>Correctly spelled?</h1>';
if ($spellcheckResult->getCorrectlySpelled()) {
echo 'yes';
} else {
echo 'no';
}
echo '<h1>Suggestions</h1>';
foreach ($spellcheckResult as $suggestion) {
echo 'NumFound: '.$suggestion->getNumFound().'<br/>';
echo 'StartOffset: '.$suggestion->getStartOffset().'<br/>';
echo 'EndOffset: '.$suggestion->getEndOffset().'<br/>';
echo 'OriginalFrequency: '.$suggestion->getOriginalFrequency().'<br/>';
foreach ($suggestion->getWords() as $word) {
echo '-----<br/>';
echo 'Frequency: '.$word['freq'].'<br/>';
echo 'Word: '.$word['word'].'<br/>';
}
echo '<hr/>';
}
$collations = $spellcheckResult->getCollations();
echo '<h1>Collations</h1>';
foreach ($collations as $collation) {
echo 'Query: '.$collation->getQuery().'<br/>';
echo 'Hits: '.$collation->getHits().'<br/>';
echo 'Corrections:<br/>';
foreach ($collation->getCorrections() as $input => $correction) {
echo $input . ' => ' . $correction .'<br/>';
}
echo '<hr/>';
}
htmlFooter();
```
For a description of the Solr StatsComponent see the [http://wiki.apache.org/solr/StatsComponent Solr wiki page](http://wiki.apache.org/solr/StatsComponent_Solr_wiki_page "wikilink").
Options
-------
| Name | Type | Default value | Description |
|-------|---------|---------------|------------------------------------------------|
| field | string | null | Field to create stats for |
| facet | boolean | null | Return sub-results for values within the facet |
||
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setRows(0);
// add stats settings
$stats = $query->getStats();
$stats->addFacet('inStock');
$stats->createField('popularity');
$stats->createField('price')->addFacet('price')->addFacet('popularity');
// this executes the query and returns the result
$resultset = $client->select($query);
$statsResult = $resultset->getStats();
// display the stats results
foreach ($statsResult as $field) {
echo '<h1>' . $field->getName() . '</h1>';
echo 'Min: ' . $field->getMin() . '<br/>';
echo 'Max: ' . $field->getMax() . '<br/>';
echo 'Sum: ' . $field->getSum() . '<br/>';
echo 'Count: ' . $field->getCount() . '<br/>';
echo 'Missing: ' . $field->getMissing() . '<br/>';
echo 'SumOfSquares: ' . $field->getSumOfSquares() . '<br/>';
echo 'Mean: ' . $field->getMean() . '<br/>';
echo 'Stddev: ' . $field->getStddev() . '<br/>';
echo '<h2>Field facets</h2>';
foreach ($field->getFacets() as $field => $facet) {
echo '<h3>Facet ' . $field . '</h3>';
foreach ($facet as $facetStats) {
echo '<h4>Value: ' . $facetStats->getValue() . '</h4>';
echo 'Min: ' . $facetStats->getMin() . '<br/>';
echo 'Max: ' . $facetStats->getMax() . '<br/>';
echo 'Sum: ' . $facetStats->getSum() . '<br/>';
echo 'Count: ' . $facetStats->getCount() . '<br/>';
echo 'Missing: ' . $facetStats->getMissing() . '<br/>';
echo 'SumOfSquares: ' . $facetStats->getSumOfSquares() . '<br/>';
echo 'Mean: ' . $facetStats->getMean() . '<br/>';
echo 'Stddev: ' . $facetStats->getStddev() . '<br/>';
}
}
echo '<hr/>';
}
htmlFooter();
```
Use the select method of the client to execute the select query object.
See the example code below.
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createQuery($client::QUERY_SELECT);
// this executes the query and returns the result
$resultset = $client->execute($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
In most cases you will reuse queries a lot. Or only slightly modify them by user input. The query model of Solarium allows for easy query modification.
There are multiple ways to do this, depending on your use case and personal preference. The example below shows two ways to do this:
```php
<?php
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\QueryType\Select\Query\Query as Select;
htmlHeader();
// create a client instance
$client = new Client($config);
// first create a base query as a query class
class PriceQuery extends Select
{
protected function init()
{
parent::init();
// set a query (all prices starting from 12)
$this->setQuery('price:[12 TO *]');
// set start and rows param (comparable to SQL limit) using fluent interface
$this->setStart(2)->setRows(20);
// set fields to fetch (this overrides the default setting 'all fields')
$this->setFields(array('id','name','price'));
// sort the results by price ascending
$this->addSort('price', self::SORT_ASC);
}
}
// the query instance easily be altered based on user input
// try calling this page with "?start=10" added to the url.
$query = new PriceQuery();
if (isset($_GET['start']) && is_numeric($_GET['start'])) {
$query->setStart($_GET['start']);
}
// alternatively you can use class inheritance to create query inheritance
// in this example this class isn't actually used, but you can simple replace
// the var $query with an instance of this class...
class LowerPriceQuery extends PriceQuery
{
protected function init()
{
// this call makes sure we get all the settings of the parent class
parent::init();
$this->setQuery('price:[5 TO *]');
}
}
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
For a general description of components see this page: [Components](V3:Components "wikilink")
In a select query result object you can get a component result in two ways:
- by using the `getComponent` method
- by using one of the component-specific `get` methods, for instance `getFacetSet`
In the following sections the available component results will be described. No every component has a result, for instance the DisMax component only influences how the query is executed, but has no result (other than the normal query response).
The facetset component result object is a collection of facet results. You can fetch a specific facet result or iterate all facet results. The results of the various facet types are described below.
Facet field
-----------
A facet field result has multiple counts, one for each term. You can get the counts using the `getValues`, this will return an array with the terms as key and the counts as values.
Even easier is using the `Iterable` interface of this result. It will return terms as keys and counts as values.
You can also use the `Countable` interface to get the number of counts.
**Example:**
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet field instance and set options
$facetSet->createFacetField('stock')->setField('inStock');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
Facet query
-----------
A facet query result is really simple. It has just one value: the count. You can access it by using it's `getValue` method.
**Example:**
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet query instance and set options
$facetSet->createFacetQuery('stock')->setQuery('inStock: true');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet query count
$count = $resultset->getFacetSet()->getFacet('stock')->getValue();
echo '<hr/>Facet query count : ' . $count;
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
Facet multiquery
----------------
A multiquery facet is basically a combination of multiple facet query instances. It works similar to the facet field, using query keys as keys and counts as values.
**Example:**
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet query instance and set options
$facet = $facetSet->createFacetMultiQuery('stock');
$facet->createQuery('stock_pricecat1', 'inStock:true AND price:[1 TO 300]');
$facet->createQuery('nostock_pricecat1', 'inStock:false AND price:[1 TO 300]');
$facet->createQuery('stock_pricecat2', 'inStock:true AND price:[300 TO *]');
$facet->createQuery('nostock_pricecat2', 'inStock:false AND price:[300 TO *]');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Multiquery facet counts:<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $key => $count) {
echo $key . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
Facet range
-----------
A range facet is also similar to a facet field, but instead of field value counts you get range counts. In addition you can get the 'before' , 'between' and 'after' count (if you specified this in the query)
**Example:**
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get the facetset component
$facetSet = $query->getFacetSet();
// create a facet field instance and set options
$facet = $facetSet->createFacetRange('priceranges');
$facet->setField('price');
$facet->setStart(1);
$facet->setGap(100);
$facet->setEnd(1000);
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet ranges:<br/>';
$facet = $resultset->getFacetSet()->getFacet('priceranges');
foreach ($facet as $range => $count) {
echo $range . ' to ' . ($range + 100) . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
The result format for the grouping format can differ quite a lot, based on the options you use. If you use the mainResult option the grouping results are returned as a normal resultset. In that case there is no grouping resultset. In all other cases the normal resultset will be empty and any documents found will be inside the groups. So instead of iterating the resultset like you normally would you need to use the grouping component result as your main resultset. Also mind that in this case the 'numFound' value of the main resultset will be NULL, as any results found are inside the grouping result.
On top of that there are two different group formats: field groups and query groups.
For query groups the query is used as the key for the group. Inside the group you can access some data like numFound and maximumScore, and a set of documents. You can see it in action in the example below.
The field group is a little more complicated. The field name is used as key for the group(s). Inside these 'fieldGroups' there is some data like 'matches' and 'numberOfGroups' (the last one only when activated in the query). And there is a collection of 'valueGroups'. These are subgroups for each unique value in the field. In each valueGroup there is a 'numFound' value and a set of documents. Again, see the example below to get the idea.
In most cases only one type of grouping is used, but you can mix any number of query groups with field groups. If you do so, be careful to handle each group in the right way based on the type of group as they are clearly not compatible.
Examples
--------
Grouped by field: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setRows(50);
// get grouping component and set a field to group by
$groupComponent = $query->getGrouping();
$groupComponent->addField('inStock');
// maximum number of items per group
$groupComponent->setLimit(3);
// get a group count
$groupComponent->setNumberOfGroups(true);
// this executes the query and returns the result
$resultset = $client->select($query);
$groups = $resultset->getGrouping();
foreach ($groups as $groupKey => $fieldGroup) {
echo '<h1>'.$groupKey.'</h1>';
echo 'Matches: '.$fieldGroup->getMatches().'<br/>';
echo 'Number of groups: '.$fieldGroup->getNumberOfGroups();
foreach ($fieldGroup as $valueGroup) {
echo '<h2>'.(int)$valueGroup->getValue().'</h2>';
foreach ($valueGroup as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
}
}
htmlFooter();
```
Grouped by query: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// get grouping component and create two query groups
$groupComponent = $query->getGrouping();
$groupComponent->addQuery('price:[0 TO 99.99]');
$groupComponent->addQuery('price:[100 TO *]');
// sorting inside groups
$groupComponent->setSort('price desc');
// maximum number of items per group
$groupComponent->setLimit(5);
// this executes the query and returns the result
$resultset = $client->select($query);
$groups = $resultset->getGrouping();
foreach ($groups as $groupKey => $group) {
echo '<h1>'.$groupKey.'</h1>';
foreach ($group as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
}
htmlFooter();
```
Results of the Highlighting component are included with the query resultset, but not directly coupled to the resulting documents. Just like in the Solr response data it is a separate dataset. However the Highlighting resultset has a method to easily access HLT results for a specific document by id (the id depends on your schema).
In the example code below you can see it in use. For each document the HLT result is fetched. This result has an array of highlighted fields (the fields you chose to highlight in your query that also had a match for this doc).
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
$query->setQuery('memory');
// get highlighting component and apply settings
$hl = $query->getHighlighting();
$hl->setFields('name, features');
$hl->setSimplePrefix('<b>');
$hl->setSimplePostfix('</b>');
// this executes the query and returns the result
$resultset = $client->select($query);
$highlighting = $resultset->getHighlighting();
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table><br/><b>Highlighting results:</b><br/>';
// highlighting results can be fetched by document id (the field defined as uniquekey in this schema)
$highlightedDoc = $highlighting->getResult($document->id);
if ($highlightedDoc) {
foreach ($highlightedDoc as $field => $highlight) {
echo implode(' (...) ', $highlight) . '<br/>';
}
}
}
htmlFooter();
```
Results of the MoreLikeThis component are included with the query resultset, but not directly coupled to the resulting documents. Just like in the Solr response data it is a separate dataset. However the MoreLikeThis resultset has a method to easily access MLT results for a specific document by id (the id depends on your schema).
In the example code below you can see it in use. For each document the MLT result is fetched. This result is an instance of Solarium\\QueryType\\Select\\Result\\MoreLikeThis\\MoreLikeThis and contains all similar documents for a result. So, as also described in the Solr MLT wiki page, in this case the name MoreLikeThese might be better.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// add a query and morelikethis settings (using fluent interface)
$query->setQuery('apache')
->getMoreLikeThis()
->setFields('manu,cat')
->setMinimumDocumentFrequency(1)
->setMinimumTermFrequency(1);
// this executes the query and returns the result
$resultset = $client->select($query);
$mlt = $resultset->getMoreLikeThis();
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table><br/><b>MLT results:</b><br/>';
// mlt results can be fetched by document id (the field defined as uniquekey in this schema)
$mltResult = $mlt->getResult($document->id);
if ($mltResult) {
echo 'Max score: '.$mltResult->getMaximumScore().'<br/>';
echo 'NumFound: '.$mltResult->getNumFound().'<br/>';
echo 'Num. fetched: '.count($mltResult).'<br/>';
foreach ($mltResult as $mltDoc) {
echo 'MLT result doc: '. $mltDoc->name . ' (id='. $mltDoc->id . ')<br/>';
}
} else {
echo 'No MLT results';
}
}
htmlFooter();
```
The result of an update query is an instance of `Solarium_Result_Select`
Data
----
### Status
Solr status code. This is not the HTTP status code! The normal value for success is 0. In case of an error an exception will be thrown. Only available if your Solr server sends headers (omitHeader=false)
### Querytime
Solr index query time. This doesn't include things like the HTTP response time. Only available if your Solr server sends headers (omitHeader=false)
### NumFound
Total number of documents that matched the query. This is not necessarily the same as the number of document in the resultset, depending on you query settings!
### Documents
The documents returned be Solr, parsed into documentClass instances. If your query has a limit of 0 or returned no results this can be an empty set.
### Components
For component results see the next sections of this manual.
Interfaces
----------
This resultclass implements the `Iterator` and `Countable` interfaces.
The iterator iterates the documentset. So you can easily loop all documents by using a `foreach`.
The countable interface returns the number of documents in this resultset. This is only the number of fetched documents! If you want the query result count you must use the numFound value.
Example
-------
A basic usage example: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createQuery($client::QUERY_SELECT);
// this executes the query and returns the result
$resultset = $client->execute($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
// the documents are also iterable, to get all fields
foreach ($document as $field => $value) {
// this converts multivalue fields to a comma-separated string
if (is_array($value)) {
$value = implode(', ', $value);
}
echo '<tr><th>' . $field . '</th><td>' . $value . '</td></tr>';
}
echo '</table>';
}
htmlFooter();
```
With select queries you can select documents and/or facet counts from your Solr index. Solr select queries have lots of options. See the following pages for an intro:
- <http://wiki.apache.org/solr/CommonQueryParameters>
- <http://wiki.apache.org/solr/SearchHandler>
- <http://wiki.apache.org/solr/SimpleFacetParameters>
A suggester query is a fast way to create an autocomplete feature. For more info on the Solr suggester component see: <http://wiki.apache.org/solr/Suggester>
Building a suggester query
--------------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|-----------------|---------|---------------|----------------------------------------------------------------------------------------|
| query | string | null | Query to spellcheck |
| dictionary | string | null | The name of the dictionary to use |
| onlymorepopular | boolean | null | Only return suggestions that result in more hits for the query than the existing query |
| collate | boolean | null | |
||
Executing a terms query
-----------------------
Use the `suggester` method of the client to execute the query object. See the example code below.
Result of a terms query
-----------------------
The result of a terms query offers direct access to the resulting suggestions, and can also be iterated.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a suggester query instance
$query = $client->createSuggester();
$query->setQuery('ap ip v'); //multiple terms
$query->setDictionary('suggest');
$query->setOnlyMorePopular(true);
$query->setCount(10);
$query->setCollate(true);
// this executes the query and returns the result
$resultset = $client->suggester($query);
echo '<b>Query:</b> '.$query->getQuery().'<hr/>';
// display results for each term
foreach ($resultset as $term => $termResult) {
echo '<h3>' . $term . '</h3>';
echo 'NumFound: '.$termResult->getNumFound().'<br/>';
echo 'StartOffset: '.$termResult->getStartOffset().'<br/>';
echo 'EndOffset: '.$termResult->getEndOffset().'<br/>';
echo 'Suggestions:<br/>';
foreach ($termResult as $result) {
echo '- '.$result.'<br/>';
}
echo '<hr/>';
}
// display collation
echo 'Collation: '.$resultset->getCollation();
htmlFooter();
```
A terms query provides access to the indexed terms in a field. For details see: <http://wiki.apache.org/solr/TermsComponent>
Building a terms query
----------------------
See the example code below.
**Available options:**
| Name | Type | Default value | Description |
|-------------------|---------|---------------|-----------------------------------------------|
| fields | string | null | Comma separated list of fields |
| lowerbound | string | null | Set the lowerbound term to start at |
| lowerboundinclude | boolean | null | |
| mincount | int | null | |
| maxcount | int | null | |
| prefix | string | null | Set prefix for terms |
| regex | string | null | Set regex to restrict terms |
| regexflags | string | null | Comma separated list of regex flags |
| limit | int | null | If &lt;0 all terms are included |
| upperbound | string | null | |
| upperboundinclude | boolean | null | |
| raw | boolean | null | Return raw characters of the term |
| sort | string | null | Set sorting of the terms ('count' or 'index') |
||
Executing a terms query
-----------------------
Use the `terms` method of the client to execute the query object. See the example code below.
Result of a terms query
-----------------------
The result of a terms query offers direct access to the resulting terms, and can also be iterated.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a terms query instance
$query = $client->createTerms();
$query->setFields('features,name');
$query->setLowerbound('i');
// this executes the query and returns the result
$resultset = $client->terms($query);
// display terms
foreach ($resultset as $field => $terms) {
echo '<h3>' . $field . '</h3>';
foreach ($terms as $term => $count) {
echo $term . ' (' . $count . ')<br/>';
}
echo '<hr/>';
}
htmlFooter();
```
Here are some tips and best practices for using update queries. Some are related to use of the Solarium library, some are general Solr usage tips.
### Combine commands
The update query can issue multiple commands in a single request, even commands of different types. So if you need to execute some deletes and add some documents you can do this in a single request. This is much more efficient than multiple requests.
### Command order
If you combine multiple commands in a single update they will be executed in the exact order they were added. So an add command followed by a delete all query will result in an empty index!
### Combine commands of the same type
If you need to add 15 documents try to use a single add command with 15 documents, instead of 15 separate add commands with a single document. The same goes for multiple deletes.
### Don't build huge update queries
Combining multiple commands into a single update request is efficient, but don't go too far with this. If you build huge update requests you might reach request limits or have other issues. And if any command fails further execution of your commands by Solr will stop, resulting in partially executed update query. This mainly occurs with bulk imports, use the BufferedAdd plugin for bulk imports.
### Use a commit manager
For performance it's important to avoid concurrent Solr commit and optimize commands. You can issue concurrent update queries without commit/optimize commands safely, but you should only do one commit at a time. You can solve this by using a commit manager, a single point for issueing commits that avoids concurrent commits. This can be a manager in your application, but most times the Solr autocommit option is sufficient.
### Don't use rollbacks
If you need to use rollbacks (outside of testing) that usually indicates there is something wrong with your update strategy. Try to find the root cause of the faulty updates, instead of rolling them back.
### Optimizing
While 'optimizing' sounds like it's always a good thing to do, you should use it with care, as it can have a negative performance impact *during the optimize process*. If possible use try to use it outside peak hours / at intervals.
This command commits add documents to the index. If a document with the same uniquekey (see Solr schema) already exists it will be overwritten, effectively updating the document.
You can add multiple documents in a single add command, this is also more efficient than separate add commands.
Options
-------
| Name | Type | Default value | Description |
|--------------|---------|---------------|-----------------------------------------------------------------------------------------------------------------|
| overwrite | boolean | null | Newer documents will replace previously added documents with the same uniqueKey |
| commitwithin | int | null | If the "commitWithin" attribute is present, the document will be added within that time (value in milliseconds) |
||
For all options:
- If no value is set (null) the param will not be sent to Solr and Solr will use it's default setting.
- See Solr documentation for details of the params
Atomic updates
--------------
Solr 4+ supports atomic updates. You can use the 'setFieldModifier' and 'setVersion' method in the document class to enable atomic updates. By default the 'old' full document update mode is used.
Examples
--------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// create a new document for the data
$doc1 = $update->createDocument();
$doc1->id = 123;
$doc1->name = 'testdoc-1';
$doc1->price = 364;
// and a second one
$doc2 = $update->createDocument();
$doc2->id = 124;
$doc2->name = 'testdoc-2';
$doc2->price = 340;
// add the documents and a commit command to the update query
$update->addDocuments(array($doc1, $doc2));
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
An update query has options and commands. These commands and options are instructions for the client classes to build and execute a request and return the correct result. In the following sections both the options and commands will be discussed in detail. You can also take a look at <http://wiki.apache.org/solr/UpdateXmlMessages> for more information about the underlying Solr update handler XML request format.
Options
-------
The update query has only two options, and it's not likely you need alter them. For select queries it's not uncommon to have a custom Solr handler, or a custom resultclass that maps to your models. But for an update query you usually just want to use the default handler and check the result. For this the default settings are just fine.
However, if you do need to customize them for a special case, you can.
### ResultClass
If you want to use a custom result class you can set the class name with this option. Any custom result class should implement the ResultInterface. It is your responsibility to make sure this class is included before use (or available through autoloading).
### Handler
The handler is used for building the Solr URL. The default value is 'update' and it's very uncommon to need to change this. But if you have a special update handler configured in your Solr core you can use this option to route update requests to this handler.
The handler value should not start or end with a slash, but may contain slashes. For instance 'admin/ping' for the ping handler is valid.
Commands
--------
Commands are the most important part of an update request. An update request may contain any combination of commands in any order. The commands will be added to the request in the exact order that you add them, and will be executed by Solr in exactly that order.
So if you were to add a 'delete' command followed by a 'rollback' command than the delete command will have no effect. (assuming there is no autocommit on the Solr server)
Examples
--------
These are two examples of update query usages. See the following sections for the details and examples of all available commands.
Add documents: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// create a new document for the data
$doc1 = $update->createDocument();
$doc1->id = 123;
$doc1->name = 'testdoc-1';
$doc1->price = 364;
// and a second one
$doc2 = $update->createDocument();
$doc2->id = 124;
$doc2->name = 'testdoc-2';
$doc2->price = 340;
// add the documents and a commit command to the update query
$update->addDocuments(array($doc1, $doc2));
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
Delete by query: ```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete query and a commit command to the update query
$update->addDeleteQuery('name:testdoc*');
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
This command commits any buffered commands to the index. This buffering is done by the Solr server, depending on the configuration. It's a global buffer, so a commit command might also commit commands that where buffered from a previous update request that had no commit command.
If you use the autoCommit feature on the Solr core you probably don't want to use the commit command, because that would trigger a commit in between the autoCommit interval. In all other cases it makes sense to add a commit to your update (or at least to the last update request if you issue multiple) to apply your update to the Solr index.
This command command starts the commit process on the server, bit the actual commit process might take a while. If your update command with a commit returns successfully this only means Solr received the commands and is processing them, the result might not be visible for a while. The time this takes depends on many factors: hardware, index size, number of index segments, the commands to execute, the search load, etcetera. It can vary between milliseconds and minutes.
Options
-------
| Name | Type | Default value | Description |
|----------------|---------|---------------|-------------------------------------------------------------------------------------------------------------|
| softcommit | boolean | null | Enable or disable softCommit |
| waitsearcher | boolean | null | Block until a new searcher is opened and registered as the main query searcher, making the changes visible. |
| expungedeletes | boolean | null | Merge segments with deletes away (available since solr 1.4) |
||
For all options:
- If no value is set (null) the param will not be sent to Solr and Solr will use it's default setting.
- See Solr documentation for details of the params
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete id and a commit command to the update query
$update->addDeleteById(123);
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
This command commits deletes documents from the index. You can delete based on document id (uniquekey) or by query. Multiple ids, multiple queries or a combination of both can be used in a single delete command.
The addDeleteQuery method supports placeholders, similar to the placeholder syntax for select queries.
Options
-------
There are no options.
Examples
--------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete query and a commit command to the update query
$update->addDeleteQuery('name:testdoc*');
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete id and a commit command to the update query
$update->addDeleteById(123);
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
You can use this command to optimize your Solr index. Optimizing 'defragments' your index. The space taken by deleted document data is reclaimed and can merge the index into fewer segments. This can improve search performance a lot.
See this page: <http://wiki.apache.org/solr/SolrPerformanceFactors#Optimization_Considerations> for more info about optimizing.
While 'optimizing' sounds like it's always a good thing to do, you should use it with care, as it can have a negative performance impact *during the optimize process*. If possible use try to use it outside peak hours.
Options
-------
| Name | Type | Default value | Description |
|--------------|---------|---------------|-------------------------------------------------------------------------------------------------------------|
| softcommit | boolean | null | Enable or disable softCommit |
| waitsearcher | boolean | null | Block until a new searcher is opened and registered as the main query searcher, making the changes visible. |
| maxsegments | int | null | Optimizes down to at most this number of segments. (available since Solr 1.3) |
||
For all options:
- If no value is set (null) the param will not be sent to Solr and Solr will use it's default setting.
- See Solr documentation for details of the params
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// optimize the index
$update->addOptimize(true, false, 5);
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
A rollback command withdraws any uncommitted changes.
If you want to use this be carefull not to have the Solr autocommit feature enabled. However in most cases you should try to prevent having to rollback changes. Rollbacks can almost always be avoided by a solid update policy.
Options
-------
This command has no options.
Example
-------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// rollback any uncommitted changes on the Solr server
$update->addRollback();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
Use the update method of the client to execute the update query object.
See the example code below.
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get an update query instance
$update = $client->createUpdate();
// add the delete id and a commit command to the update query
$update->addDeleteById(123);
$update->addCommit();
// this executes the query and returns the result
$result = $client->update($update);
echo '<b>Update query executed</b><br/>';
echo 'Query status: ' . $result->getStatus(). '<br/>';
echo 'Query time: ' . $result->getQueryTime();
htmlFooter();
```
The result of an update has two result values (both reported by Solr in the response):
- status: Solr status code. This is not the HTTP status code! The normal value for success is 0.
- querytime: Solr index query time. This doesn't include things like the HTTP responsetime.
By default 'omitHeader' is enabled so these results are missing. If you need the status and/or querytime you can call setOmitHeader(false) on your update query before execution.
In case of an error an exception will be thrown.
Update queries allow you to add, delete, commit, optimize and rollback commands. For all the details about the Solr update handler please see the Solr documentation, but some important notes:
- Solr has no 'update' command. But if you add a document with a value for the 'unique key' field that already exists in the index that existing document will be overwritten by your new document.
- You can only add complete documents. If you want to update only a single field you still need to 'add' the whole document.
- Always use a database or other persistent storage as the source for building documents to add. Don't be tempted to emulate an update command by selecting a document, altering it and adding it. Almost all schemas will have fields that are indexed and not stored. You will loose the data in those fields.
- The best way to use update queries is also related to your Solr config. If you are for instance using the autocommit feature of Solr you probably don't want to use a commit command in your update queries. Make sure you know the configuration details of the Solr core you use.
Solarium concepts
=================
This section explains the concepts used by Solarium. It's not necessary to know this to use Solarium, but it will give you a better understanding of all the parts involved in handling a request. Especially useful if you want to work on the Solarium code, write an extension, or want to debug some issues you might encounter.
Usage modes
===========
Solarium allows for three main modes of usage of the library: programmatically, by extending or by configuration. They all have there own pros and cons, the most optimal solution depends on your use case and also your personal preference. You can even mix the different modes if you want to, for instance creating a select query based on a config and programmatically changing it.
Currently only the programmatic and extending modes support all features, the configuration mode doesn't support some complex cases. This might be improved over time but there will always be limits to what is possible with configuration only, without creating very complex configurations.
The configuration mode supports an array as input or an object that implements the `toArray()` method (this is also compatible with the Zend Framework `Zend_Config` component).
The three modes apply to all Solarium classes that extend `Solarium\Core\Configurable`. This includes all Solarium classes that are intended for direct usage, e.g. the query classes, filterqueries, components etcetera. You can check to API for a class to see if it supports config mode.
As an example the three modes are demonstrated, all creating an identical Solr client instance:
API example
-----------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance
$query = $client->createSelect();
// apply settings using the API
$query->setQuery('*:*');
$query->setStart(2)->setRows(20);
$query->setFields(array('id','name','price'));
$query->addSort('price', $query::SORT_ASC);
// create a filterquery using the API
$fq = $query->createFilterQuery('maxprice')->setQuery('price:[1 TO 300]');
// create a facet field instance and set options using the API
$facetSet = $query->getFacetSet();
$facet = $facetSet->createFacetField('stock')->setField('inStock');
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
Configuration example
---------------------
```php
<?php
require(__DIR__.'/init.php');
htmlHeader();
// In this case an array is used for configuration to keep the example simple.
// For an easier to use config file you are probably better of with another format, like Zend_Config_Ini
// See the documentation for more info about this.
$select = array(
'query' => '*:*',
'start' => 2,
'rows' => 20,
'fields' => array('id','name','price'),
'sort' => array('price' => 'asc'),
'filterquery' => array(
'maxprice' => array(
'query' => 'price:[1 TO 300]'
),
),
'component' => array(
'facetset' => array(
'facet' => array(
// notice this config uses an inline key value, instead of array key like the filterquery
array('type' => 'field', 'key' => 'stock', 'field' => 'inStock'),
)
),
),
);
// create a client instance
$client = new Solarium\Client($config);
// get a select query instance based on the config
$query = $client->createSelect($select);
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
Extending example
-----------------
```php
<?php
require(__DIR__.'/init.php');
use Solarium\Client;
use Solarium\QueryType\Select\Query\Query as Select;
htmlHeader();
// In most cases using the API or config is advisable, however in some cases it can make sense to extend classes.
// This makes it possible to create 'query inheritance' like in this example
class ProductQuery extends Select
{
protected function init()
{
parent::init();
// basic params
$this->setQuery('*:*');
$this->setStart(2)->setRows(20);
$this->setFields(array('id','name','price'));
$this->addSort('price', self::SORT_ASC);
// create a facet field instance and set options
$facetSet = $this->getFacetSet();
$facetSet->createFacetField('stock')->setField('inStock');
}
}
// This query inherits all of the query params of its parent (using parent::init) and adds some more
// Ofcourse it could also alter or remove settings
class ProductPriceLimitedQuery extends ProductQuery
{
protected function init()
{
parent::init();
// create a filterquery
$this->createFilterQuery('maxprice')->setQuery('price:[1 TO 300]');
}
}
// create a client instance
$client = new Client($config);
// create a query instance
$query = new ProductPriceLimitedQuery;
// this executes the query and returns the result
$resultset = $client->select($query);
// display the total number of documents found by solr
echo 'NumFound: '.$resultset->getNumFound();
// display facet counts
echo '<hr/>Facet counts for field "inStock":<br/>';
$facet = $resultset->getFacetSet()->getFacet('stock');
foreach ($facet as $value => $count) {
echo $value . ' [' . $count . ']<br/>';
}
// show documents using the resultset iterator
foreach ($resultset as $document) {
echo '<hr/><table>';
echo '<tr><th>id</th><td>' . $document->id . '</td></tr>';
echo '<tr><th>name</th><td>' . $document->name . '</td></tr>';
echo '<tr><th>price</th><td>' . $document->price . '</td></tr>';
echo '</table>';
}
htmlFooter();
```
Structure and queryflow
=======================
TODO
Best practices
==============
In the following sections of this manual various parts of Solarium are described in detail, including best practices specific for those parts. This page lists some best practices for Solarium in general.
### Lazy loading
Solarium tries to use lazy-loading as much as possible. For instance a select query component is only added to a query when you actually use it. And a Solr result is only parsed at the moment you access the data. In your application you will usually build a layer on top of Solarium. Make sure this layer is also lazy-loading, else you will lose the benefits. Some examples:
- don't add all components you *might need* to the query. Only add them on actual use.
- only construct a query if you are actually going to use it
- don't copy the data in the result objects but use the iterators or access methods. This prevents disabling the lazy-loading mechanism and also prevents data duplication.
One exception can be the Solarium client instance itself. Instantiating a Solarium\\Client instance has been made lightweight so you can have it ready at all times by adding it to a bootstrap, similar to a database access layer. However, there is still a small overhead so if you only use Solr on a small number of pages you might still be better of only loading it on those pages.
### Create methods
There are create methods for almost all Solarium classes. Instead of creating an instance of a specific (long) classname you can use a create method. For instance to create a select query:
`$select = $client->createSelect();`
Besides ease-of-use there is another important reason for these 'create' methods. The create methods use a class mapping. Plugins have the ability to customize class mappings, however this won't work if you directly instantiate classes yourself.
So while it is still possible to create class instances manually, it is advisable to use the create methods. Ideally you should only manually create an instance of 'Solarium\\Client', and use create methods for all other Solarium object instances (for instance filterqueries, facets, update commands and documents).
### Customizing Solarium
If you want to customize Solarium please read the docs on this first. While you can simply extend classes that's in most cases not the best way to go.
### Response parser format
Solarium supports two Solr responsewriters: json and phps. The ‘phps’ responsewriter returns data as serialized PHP. This can be more efficient to decode than json, especially for large responses. For a benchmark see [http://www.raspberry.nl/2012/02/28/benchmarking-php-solr-response-data-handling/ this blogpost](http://www.raspberry.nl/2012/02/28/benchmarking-php-solr-response-data-handling/_this_blogpost "wikilink") (but be sure to test for your own use-case)
However this comes at the cost of a possible security risk in PHP deserialization. As long as you use a trusted Solr server this should be no issue, but to be safe the default is still JSON.
You can switch to the phps responseparser by setting a query option:
`$query = $client->createQuery($client::QUERY_SELECT, array('responsewriter' => 'phps'));`
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment