Set-up and configuration #
Getting started #
In order to return search results, Solr requires an Index that holds the searchable data.
So the first thing you need to do is to create an index extending the
Firesphere\SolrSearch\Indexes\BaseIndex
class, or if you are using the compatibility
module, the SilverStripe\FullTextSearch\Solr\SolrIndex
class.
If you are extending the base Index, it will require a getIndexName
method
which is used to determine the name of the index to query Solr.
Although the compatibility module provides a core naming scheme, it is still highly recommended to implement your own method.
IMPORTANT
The usage of YML
for the core configuration is not a replacement for creating your own Index
extending either of the Base Indexes; it is a complement to it.
YML
is purely used for the configuration of the index Classes.
Configuration #
Configuring Solr is done via YML:
Firesphere\SolrSearch\Services\SolrCoreService:
config:
endpoint:
myhostname:
host: myhost.com
port: 8983
timeout: 10
# set up timeouts
index_timeout: 10
optimize_timeout: 100
finalize_timeout: 300
http_method: 'AUTO'
# commit within 60ms
commit_within: 60
# default path settings
store:
path: '.solr'
cpucores: 2
debug: false
Note #
If you are using defaults (localhost), it is not necessary to add this to your configuration.
The config is used to connect to Solr. This will tell the module where the Solr instance for this index lives and how to connect.
The store is to select the way to configure the solr configuration storage. Available stores are FileConfigStore
which requires path, or PostConfigStore
and a required endpoint to post to.
Example POST Store config:
---
Name: 'MySearch'
After:
- 'SolrSearch'
---
Firesphere\SolrSearch\Services\SolrCoreService:
store:
path: '/my_post_endpoint'
uri: 'https://mydomain.com'
And the Injector config to use the PostConfigStore:
---
Name: MySolrStore
After:
- 'SolrStore'
---
SilverStripe\Core\Injector\Injector:
Firesphere\SolrSearch\Interfaces\ConfigStore:
class: Firesphere\SolrSearch\Stores\PostConfigStore
Authentication #
Solr supports several ways of adding authentication to the instance.
The module only supports Basic Authentication, which can be added in the YML config like so:
Firesphere\SolrSearch\Services\SolrCoreService:
config:
endpoint:
myhostname:
username: solr
password: SolrRocks
Debug #
You can force the debugging to false, by setting the debug flag. If you omit this tag, CLI and Dev mode will have debugging enabled.
ShowInSearch #
ShowInSearch
is handled by the module itself, so there is no need to configure it within your YML/PHP index definition.
When a content author sets this field to 0
via the CMS, then the related Page or File object is actually removed from the applicable Solr
core immediately through the onAfterPublish
or onAfterWrite
method, or during the next run of the SolrIndexJob
.
Therefore, custom addition of ShowInSearch
as a filterable or indexable field in YML
is likely to cause unexpected behaviour.
The reason for removing ShowInSearch = false|0
from the indexing process,
is to streamline the number of items stored in Solr’s indexes.
There is no effective need for items to be in the search, if they’re not supposed to
be displayed.
Dirty classes #
If a change fails to update, a DirtyClass
is created, recording the need for updating
said object. It is recommended to automatically run the ClearDirtyClasses
task every few hours
depending on the expected amount of changes daily and the importance of those changes.
The expected time to run the task is quite low, so we recommend running this task reasonably often (every 5 or 10 minutes).
Defining the amount of CPU cores #
If your server has multiple CPU cores available, you can define the amount of cores in the config. During indexing, this means that each core is allocated an indexing of a group. The advantage is that it utilises all the cores available, speeding up the indexing process.
The amount of cores can not be determined programmatically (due to access control), so you will have to define the amount of cores available manually.
NOTE
Given the current situation in server-land, the default amount of cores is 2. This should work fine for most situations, even if you only have one core available. If you have more cores, you can make this amount larger, of course. Using all of the cores your system has will make your website pretty slow during indexing! It is advised to keep at least one core free for handling page visits while you’re running an index.
Using init() #
Similar to the FulltextSearch module, using init supports all basic methods to add fulltext or filter fields.
Available methods are:
Method | Purpose | Required | Usage |
---|---|---|---|
addClass | Add classes to index | Yes | $this->addClass(SiteTree::class); |
addFulltextField | Add fields to index | No1 | $this->addFulltextField('Content'); |
addAllFulltextField | Add all text fields to index | No | $this->addAllFulltextFields(); |
addFilterField | Add fields to use for filtering | No | $this->addFilterField('ID'); |
addBoostedField | Fields to boost by on Query time | No | $this->addBoostedField('Title', ([]/2), 2); 2 |
addSortField | Field to sort by | No | $this->addSortField('Created'); |
addCopyField | Add a special copy field, besides the default _text | No | $this->addCopyField('myCopy', ['Fields', 'To', 'Copy']); |
addStoredField | Add a field to be stored specifically | No | $this->addStoredField('LastEdited'); |
addFacetField | Field to build faceting on | No | $this->addFacetField(SiteTree::class, ['BaseClass' => SiteTree::class, 'Title' => 'FacetObject', 'Field' => 'FacetObjectID']); |
Using YML #
Firesphere\SolrSearch\Indexes\BaseIndex:
MySearchIndex:
Classes:
- SilverStripe\CMS\Model\SiteTree
FulltextFields:
- Content
- TestObject.Title
- TestObject.TestRelation.Title
SortFields:
- Created
FilterFields:
- Title
- Created
- Firesphere\SolrSearch\Tests\TestObject
BoostedFields:
- Title
CopyFields:
_text:
- '*'
DefaultField: _text
FacetFields:
Firesphere\SolrSearch\Tests\TestObject:
BaseClass: SilverStripe\CMS\Model\SiteTree
Field: ID
Title: TestObject
MySearchIndex #
This name should match the name you provided in your Index extending the BaseIndex
you are instructed
to create in the first step of this document.
Moving from init to YML #
The compatibility module has an optional extension method that allows you to build your index and then generate the YML content for you. See the compatibility module for more details.
Grouped indexing #
Be aware that Grouped indexing is 0
-based. Thus, if there are 150 groups to index,
the final group to index will be 149 instead of 150.
Method output casting #
To get the correct Solr field type in the Solr Configuration, you will need to add a
casting for each method you want to add. So for the Content
field, the method below:
public function getContent()
{
return $renderedContent;
}
Could have a casting like the below to ensure it renders as HTML:
private static $casting = [
'getContent' => 'HTMLText',
'Content' => 'HTMLText'
];
Depending on your field definition, you either need to have the full method name, or the short method name.
Another way to set the config in PHP #
You could also use PHP to set the config. For readability however, it’s better to use variables for Facets:
protected $facetFields = [
RelatedObject::class => [
'BaseClass' => SiteTree::class,
'Field' => 'RelatedObjectID',
'Title' => 'RelationOne'
],
OtherRelatedObject::class => [
'BaseClass' => SiteTree::class,
'Field' => 'OtherRelatedObjectID',
'Title' => 'RelationTwo'
]
];
This will generate a facet field in Solr, assuming this relation exists on SiteTree
or Page
.
The relation would look like SiteTree_RelatedObjectID
, where RelatedObject
the name of the relation reflects.
The Title is used to group all facets by their Title, in the template, this is accessible by looping $Result.FacetSet.TitleOfTheFacet
Important notice #
Facets are relational. For faceting on a relation, omit the origin class (e.g. SiteTree
), but supply the full relational
path to the facet. e.g. if you want to have facets on RelationObject->ManyRelation()->OneRelation()->ID
, the Facet declaration should be
ManyRelationObject.OneRelationID
, assuming it’s a has_one
relation.
If you have many relations, through either many_many
or has_many
, your definition should
use ManyRelationObjectName.Relation.ID
instead of RelationID
. It works and resolves the same.
It is strongly advised to use relations for faceting, as Solr tends to think of textual relations in a different way.
Example #
If you set relations on MyObject.TextField
, and the text field contains “Content Name
One” and “Content Name Two”, faceting would be done in such a way that “Content”, “Name”
and “One” would be three different facet results, rather than “Content Name One”.
Accessing Solr #
If available, you can access your Solr instance at http://mydomain.com:8983
Excluding unwanted indexes #
To exclude unwanted indexes, it is possible declare a list of wanted indexes in the YML
Firesphere\SolrSearch\Services\SolrCoreService:
indexes:
- CircleCITestIndex
- Firesphere\SolrSearch\Tests\TestIndex
- Firesphere\SolrSearch\Tests\TestIndexTwo
- Firesphere\SolrSearch\Tests\TestIndexThree
Looking at the tests
folder, there is a TestIndexFour
. This index is not loaded unless explicitly asked.
1 Although not required, it’s highly recommended
2 The second option of an array can be omitted and directly given the boost value