Skip to content
Snippets Groups Projects
Commit de4582fb authored by Ere Maijala's avatar Ere Maijala Committed by Demian Katz
Browse files

Added support for Solr's MoreLikeThis query handler (#730)

- When turned on, this adds MoreLikeThis support for sharded indexes in SolrCloud.
- Note that the MoreLikeThis component remains the default setting, as it provides more nuanced results as of this writing.
- Resolves VUFIND-652.
parent 142682cf
No related merge requests found
......@@ -606,3 +606,18 @@ view=full
; Priority order (descending) for record sources (record ID prefixes separated
; from the actual record by period, e.g. testsrc.12345)
;sources = alli,testsrc
; This section defines settings used to fetch similar records.
[MoreLikeThis]
; Boolean value indicating whether the newer MoreLikeThis query handler should be
; used instead of the traditional MoreLikeThis component (default). Only the
; MoreLikeThis query handler supports sharded indexes, but as of this writing, the
; traditional component offers more nuanced relevance ranking. Results from these
; methods may differ.
;useMoreLikeThisHandler = true
; If the MoreLikeThis handler is used, this setting can be used to adjust its
; behavior. See https://cwiki.apache.org/confluence/display/solr/Other+Parsers#OtherParsers-MoreLikeThisQueryParser
; for more information regarding the possible parameters.
;params = "qf=title,title_short,callnumber-label,topic,language,author,publishDate mintf=1 mindf=1";
; This setting can be used to limit the maximum number of suggestions. Default is 5.
;count = 5
......@@ -42,6 +42,7 @@ use VuFind\Search\Solr\HierarchicalFacetListener;
use VuFindSearch\Backend\BackendInterface;
use VuFindSearch\Backend\Solr\LuceneSyntaxHelper;
use VuFindSearch\Backend\Solr\QueryBuilder;
use VuFindSearch\Backend\Solr\SimilarBuilder;
use VuFindSearch\Backend\Solr\HandlerMap;
use VuFindSearch\Backend\Solr\Connector;
use VuFindSearch\Backend\Solr\Backend;
......@@ -156,6 +157,7 @@ abstract class AbstractSolrBackendFactory implements FactoryInterface
{
$backend = new Backend($connector);
$backend->setQueryBuilder($this->createQueryBuilder());
$backend->setSimilarBuilder($this->createSimilarBuilder());
if ($this->logger) {
$backend->setLogger($this->logger);
}
......@@ -372,6 +374,18 @@ abstract class AbstractSolrBackendFactory implements FactoryInterface
return $builder;
}
/**
* Create the similar records query builder.
*
* @return SimilarBuilder
*/
protected function createSimilarBuilder()
{
return new SimilarBuilder(
$this->config->get($this->searchConfig), $this->uniqueKey
);
}
/**
* Load the search specs.
*
......
......@@ -73,6 +73,13 @@ class Backend extends AbstractBackend
*/
protected $queryBuilder = null;
/**
* Similar records query builder.
*
* @var SimilarBuilder
*/
protected $similarBuilder = null;
/**
* Constructor.
*
......@@ -211,6 +218,7 @@ class Backend extends AbstractBackend
$params = $params ?: new ParamBag();
$this->injectResponseWriter($params);
$params->mergeWith($this->getSimilarBuilder()->build($id, $params));
$response = $this->connector->similar($id, $params);
$collection = $this->createRecordCollection($response);
$this->injectSourceIdentifier($collection);
......@@ -304,6 +312,33 @@ class Backend extends AbstractBackend
return $this->queryBuilder;
}
/**
* Set the similar records query builder.
*
* @param SimilarBuilder $similarBuilder Similar builder
*
* @return void
*/
public function setSimilarBuilder(SimilarBuilder $similarBuilder)
{
$this->similarBuilder = $similarBuilder;
}
/**
* Return similar records query builder.
*
* Lazy loads an empty default SimilarBuilder if none was set.
*
* @return SimilarBuilder
*/
public function getSimilarBuilder()
{
if (!$this->similarBuilder) {
$this->similarBuilder = new SimilarBuilder();
}
return $this->similarBuilder;
}
/**
* Return the record collection factory.
*
......
......@@ -185,23 +185,20 @@ class Connector implements \Zend\Log\LoggerAwareInterface
/**
* Return records similar to a given record specified by id.
*
* Uses MoreLikeThis Request Handler
* Uses MoreLikeThis Request Component or MoreLikeThis Handler
*
* @param string $id Id of given record
* @param string $id ID of given record (not currently used, but
* retained for backward compatibility / extensibility).
* @param ParamBag $params Parameters
*
* @return string
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function similar($id, ParamBag $params = null)
public function similar($id, ParamBag $params)
{
$params = $params ?: new ParamBag();
$params
->set('q', sprintf('%s:"%s"', $this->uniqueKey, addcslashes($id, '"')));
$params->set('qt', 'morelikethis');
$handler = $this->map->getHandler(__FUNCTION__);
$this->map->prepare(__FUNCTION__, $params);
return $this->query($handler, $params);
}
......
<?php
/**
* SOLR SimilarBuilder.
*
* PHP version 5
*
* Copyright (C) Villanova University 2010.
* Copyright (C) The National Library of Finland 2016.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category VuFind
* @package Search
* @author Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
* @author David Maus <maus@hab.de>
* @author Demian Katz <demian.katz@villanova.edu>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
namespace VuFindSearch\Backend\Solr;
use VuFindSearch\ParamBag;
/**
* SOLR SimilarBuilder.
*
* @category VuFind
* @package Search
* @author Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
* @author David Maus <maus@hab.de>
* @author Demian Katz <demian.katz@villanova.edu>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
class SimilarBuilder implements SimilarBuilderInterface
{
/**
* Solr field used to store unique identifier
*
* @var string
*/
protected $uniqueKey;
/**
* Whether to use MoreLikeThis Handler instead of the traditional MoreLikeThis
* component.
*
* @var bool
*/
protected $useHandler = false;
/**
* MoreLikeThis Handler parameters
*
* @var string
*/
protected $handlerParams = '';
/**
* Number of similar records to retrieve
*
* @var int
*/
protected $count = 5;
/**
* Constructor.
*
* @param \Zend\Config\Config $searchConfig Search config
* @param string $uniqueKey Solr field used to store unique
* identifier
*
* @return void
*/
public function __construct(\Zend\Config\Config $searchConfig = null,
$uniqueKey = 'id'
) {
$this->uniqueKey = $uniqueKey;
if (isset($searchConfig->MoreLikeThis)) {
$mlt = $searchConfig->MoreLikeThis;
if (isset($mlt->useMoreLikeThisHandler)
&& $mlt->useMoreLikeThisHandler
) {
$this->useHandler = true;
$this->handlerParams = isset($mlt->params) ? $mlt->params : '';
}
if (isset($mlt->count)) {
$this->count = $mlt->count;
}
}
}
/// Public API
/**
* Return SOLR search parameters based on a record Id and params.
*
* @param string $id Record Id
*
* @return ParamBag
*/
public function build($id)
{
$params = new ParamBag();
if ($this->useHandler) {
$mltParams = $this->handlerParams
? $this->handlerParams
: 'qf=title,title_short,callnumber-label,topic,language,author,'
. 'publishDate mintf=1 mindf=1';
$params->set('q', sprintf('{!mlt %s}%s', $mltParams, $id));
} else {
$params->set(
'q', sprintf('%s:"%s"', $this->uniqueKey, addcslashes($id, '"'))
);
$params->set('qt', 'morelikethis');
}
if (null === $params->get('rows')) {
$params->set('rows', $this->count);
}
return $params;
}
}
<?php
/**
* SOLR SimilarBuilder interface definition.
*
* PHP version 5
*
* Copyright (C) Villanova University 2010.
* Copyright (C) The National Library of Finland 2016.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category VuFind
* @package Search
* @author Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
* @author David Maus <maus@hab.de>
* @author Demian Katz <demian.katz@villanova.edu>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
namespace VuFindSearch\Backend\Solr;
use VuFindSearch\ParamBag;
/**
* SOLR SimilarBuilder interface definition.
*
* @category VuFind
* @package Search
* @author Andrew S. Nagy <vufind-tech@lists.sourceforge.net>
* @author David Maus <maus@hab.de>
* @author Demian Katz <demian.katz@villanova.edu>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
interface SimilarBuilderInterface
{
/**
* Build SOLR query based on VuFind query object.
*
* @param string $id Record id
*
* @return ParamBag
*/
public function build($id);
}
<?php
/**
* Unit tests for SOLR similar records query builder
*
* PHP version 5
*
* Copyright (C) Villanova University 2010.
* Copyright (C) The National Library of Finland 2016.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category VuFind
* @package Search
* @author David Maus <maus@hab.de>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
namespace VuFindTest\Backend\Solr;
use VuFindSearch\Backend\Solr\SimilarBuilder;
/**
* Unit tests for SOLR similar records query builder
*
* @category VuFind
* @package Search
* @author David Maus <maus@hab.de>
* @author Ere Maijala <ere.maijala@helsinki.fi>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org
*/
class SimilarBuilderTest extends \VuFindTest\Unit\TestCase
{
/**
* Test builder with default params.
*
* @return void
*/
public function testDefaultParams()
{
$sb = new SimilarBuilder();
$response = $sb->build('testrecord');
$rows = $response->get('rows');
$this->assertEquals(5, $rows[0]);
$q = $response->get('q');
$this->assertEquals('id:"testrecord"', $q[0]);
$qt = $response->get('qt');
$this->assertEquals('morelikethis', $qt[0]);
}
/**
* Test builder with alternative id field.
*
* @return void
*/
public function testAlternativeIdField()
{
$sb = new SimilarBuilder(null, 'key');
$response = $sb->build('testrecord');
$q = $response->get('q');
$this->assertEquals('key:"testrecord"', $q[0]);
}
/**
* Test builder with different configurations.
*
* @return void
*/
public function testMltConfig()
{
$config = [
'MoreLikeThis' => [
'count' => 10
]
];
$sb = new SimilarBuilder(new \Zend\Config\Config($config));
$response = $sb->build('testrecord');
$rows = $response->get('rows');
$this->assertEquals(10, $rows[0]);
$config['MoreLikeThis']['useMoreLikeThisHandler'] = true;
$sb = new SimilarBuilder(new \Zend\Config\Config($config));
$response = $sb->build('testrecord');
$rows = $response->get('rows');
$this->assertEquals(10, $rows[0]);
$q = $response->get('q');
$this->assertEquals(
'{!mlt qf=title,title_short,callnumber-label,topic,language,author,'
. 'publishDate mintf=1 mindf=1}testrecord',
$q[0]
);
$qt = $response->get('qt');
$this->assertEquals(null, $qt);
$config['MoreLikeThis']['params'] = 'qf=title,topic';
$sb = new SimilarBuilder(new \Zend\Config\Config($config));
$response = $sb->build('testrecord');
$q = $response->get('q');
$this->assertEquals('{!mlt qf=title,topic}testrecord', $q[0]);
}
}
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