Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search Result Explanation Feature #3069

Merged
merged 33 commits into from Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f448d03
implemented explain feature
ThoWagen Sep 5, 2023
55910ce
Merge branch 'dev' into pull-request/explain
ThoWagen Sep 5, 2023
c37a9eb
ran php-cs-fixer
ThoWagen Sep 5, 2023
e032793
Merge branch 'dev' into pull-request/explain
demiankatz Nov 6, 2023
6e9bb9c
removed spaces
ThoWagen Nov 7, 2023
ce9934b
fixed translations
ThoWagen Nov 7, 2023
7a64626
Merge branch 'dev' into pull-request/explain
ThoWagen Nov 13, 2023
56abe80
explain element view helper and fixes
ThoWagen Nov 13, 2023
a7ccbb7
bold field name
ThoWagen Nov 13, 2023
a1e758c
Merge branch 'dev' into pull-request/explain
ThoWagen Nov 16, 2023
e9ad21d
changed explain link and added translations
ThoWagen Nov 16, 2023
a908e72
explain for search2 and small fixes
ThoWagen Nov 16, 2023
5e6590e
Merge branch 'dev' into pull-request/explain
ThoWagen Nov 16, 2023
3e0ea68
support synonyms
ThoWagen Nov 17, 2023
7416282
Merge branch 'dev' into pull-request/explain
ThoWagen Nov 30, 2023
3183bc4
small fixes
ThoWagen Nov 30, 2023
2017bf8
refactored
ThoWagen Nov 30, 2023
26e2173
fixed resultlist if no explain information is provided
ThoWagen Nov 30, 2023
741641e
small fixes
ThoWagen Dec 1, 2023
5579744
always using arrays for fieldName, fieldValue and exactMatch
ThoWagen Dec 1, 2023
e5a0dcb
using translate instead of transEsc
ThoWagen Dec 6, 2023
e92a973
Merge branch 'dev' into pull-request/explain
ThoWagen Dec 6, 2023
fcaf9b9
Fix typo.
demiankatz Dec 18, 2023
5d4fb91
removed unused translation and moved added explain_ prefixes
ThoWagen Jan 11, 2024
872b956
created search2default factory
ThoWagen Jan 11, 2024
5460f06
Merge branch 'pull-request/explain' of github.com:ThoWagen/vufind int…
ThoWagen Jan 11, 2024
4089589
Merge branch 'dev' into pull-request/explain
ThoWagen Jan 11, 2024
0ea5a24
improved search2default factory
ThoWagen Jan 12, 2024
fdc11b3
fixed typos
ThoWagen Jan 12, 2024
ff69e61
added Mink test class
ThoWagen Jan 12, 2024
ca46205
fixed typo
ThoWagen Jan 12, 2024
198c4c8
added questionmark for field description
ThoWagen Jan 15, 2024
ad7d405
Merge branch 'dev' into pull-request/explain
demiankatz Jan 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.xml
Expand Up @@ -375,6 +375,8 @@
<target name="copynodemodules">
<!-- autocomplete.js -->
<copy file="${srcdir}/node_modules/autocomplete.js/autocomplete.js" todir="${srcdir}/themes/bootstrap3/js/vendor" overwrite="true" />
<!-- chart.js -->
<copy file="${srcdir}/node_modules/chart.js/dist/chart.umd.js" tofile="${srcdir}/themes/bootstrap3/js/vendor/chart.js" overwrite="true" />
<!-- jstree -->
<copy todir="${srcdir}/themes/bootstrap3/js/vendor/jsTree" overwrite="true">
<fileset dir="${srcdir}/node_modules/jstree/dist/" >
Expand Down
17 changes: 16 additions & 1 deletion config/vufind/searches.ini
Expand Up @@ -124,7 +124,8 @@ always_display_reset_filters = false
;default_filters[] = "(format:Book AND institution:MyInstitution)"

; Default record fields to fetch from Solr when searching (Solr parameter 'fl')
; Default is "*" (since VuFind 7.0). To restore previous setting, just uncomment
; Default is "*" (since VuFind 7.0). When Explain is enabled 'score' will automatically be
; added if it is not already included. To restore previous setting, just uncomment
; line below.
;default_record_fields = "*,score"

Expand Down Expand Up @@ -869,3 +870,17 @@ maxLimit = 100
; ttl, Time to Live, i.e. cache entry life time in seconds. 300 seconds by default.
;options[ttl] = 300

; This section provides settings for the explain feature. When enabled the result
; list contains links to the explanation why a title was found and how the relevance
; is calculated.
[Explain]
; The explain feature is disabled by default. Uncomment the following line to enable it
;enabled = true
EreMaijala marked this conversation as resolved.
Show resolved Hide resolved
; The explanation is split into the main fields and a rest.
; minPercent gives a lower bound for fields to be included. All fields with
; a percentage lower than minPercent are summarized in the rest.
;minPercent = 0
; maxFields gives a upper bound for the number of main fields. Set negative for no boundary.
;maxFields = -1
; Number of decimal places to be displayed.
;decimalPlaces = 2
5 changes: 5 additions & 0 deletions languages/IndexFieldDescription/de.ini
@@ -0,0 +1,5 @@
;description of fields in explain
allfields_unstemmed = 'Kopiert aus "Alle Felder"'
fulltext_unstemmed = 'Kopiert von "Volltext"'
title_alt = "alternativer Titel"
unknown = "Feldname unbekannt"
5 changes: 5 additions & 0 deletions languages/IndexFieldDescription/en.ini
@@ -0,0 +1,5 @@
;description of fields in explain
allfields_unstemmed = "copyFielded from allfields"
fulltext_unstemmed = "copyFielded from fulltext"
title_alt = "alternate title(s)"
unknown = "field name is unknown"
13 changes: 13 additions & 0 deletions languages/de.ini
Expand Up @@ -334,6 +334,7 @@ Description = "Beschreibung"
Desired Username = "Gewünschter Benutzername"
Detailed View = "Detailansicht"
Details = "Details"
Difference to top result relevance = "Differenz zu der top Relevanz"
Displaying the top = "Angezeigt werden die ersten"
Document Inspector = "Dokumentprüfer"
Document Type = "Publikationsart"
Expand Down Expand Up @@ -409,6 +410,16 @@ Exception = "Exception"
Excerpt = "Ausschnitt"
exclude_facet = "[ausschließen]"
exclude_newspapers = "Ohne Zeitungsartikel"
explain_boost = " * %%boost%% (Boost)"
explain_boost_description = "(Boost) = %%boost_description%%"
explain_compared = "Relevanz im Vergleich zu der Trefferrelevanz des Top Treffers"
explain_coord = " * %%coord%% (Ausgleich von Anzahl der Treffer im Vergleich zur Suche)"
explain_disabled = "Explain ist für %%searchClassId%% deaktiviert"
explain_modified_value = "Produkt von %%relevanceValue%% (Relevanzwert)"
explain_modifier = "mit dem Modifier: %%modifier%%"
explain_relevance = "Record Id: %%recordId%% gefunden mit einem Relevanzwert von %%relevanceValue%%"
explain_sum = "Summe"
Explanation for search = "Explain für Suche"
Export = "Export"
Export Favorites = "Favoriten exportieren"
Export Items = "Exportieren"
Expand Down Expand Up @@ -1130,6 +1141,7 @@ relais_success_message = "Bestellnummer %%id%% wurde angelegt. Sie erhalten eine
Related Author = "Ähnliche Verfasser"
Related Items = "Ähnliche Datensätze"
Related Subjects = "Ähnliche Schlagworte"
Relevance = "Relevanz"
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
Remove filter = "Suchfilter entfernen"
Remove Filters = "Suchfilter entfernen"
Remove from Book Bag = "Aus der Zwischenablage entfernen"
Expand Down Expand Up @@ -1372,6 +1384,7 @@ Too Many Email Recipients = "Zu viele E-Mail-Adressen"
too_many_favorites = "Diese Liste ist zu gross um auf einmal angezeigt zu werden. Versuchen Sie Ihre Favoriten in weitere Listen zu unterteilen oder mittels Tags einzuschränken."
too_many_new_items = "Es gibt zu viele Einträge um in einer einzigen Liste angezeigt zu werden. Versuchen Sie Ihre Suche weiter einzuschränken."
too_many_reserves = "Es gibt zu viele Vormerkungen um in einer einzigen Liste angezeigt zu werden. Versuchen Sie Ihre Suche weiter einzuschränken."
Top Result Relevance = "Top Treffer Relevanz"
top_facet_label = "%%label%% innerhalb Ihrer Suche."
Topic = "Thema"
Topics = "Themen"
Expand Down
13 changes: 13 additions & 0 deletions languages/en.ini
Expand Up @@ -336,6 +336,7 @@ Description = "Description"
Desired Username = "Desired Username"
Detailed View = "Detailed View"
Details = "Staff View"
Difference to top result relevance = "Difference to top result relevance"
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
Displaying the top = "Displaying the top"
Document Inspector = "Document Inspector"
Document Type = "Document Type"
Expand Down Expand Up @@ -411,6 +412,16 @@ Exception = "Exception"
Excerpt = "Excerpt"
exclude_facet = "Exclude matching results"
exclude_newspapers = "Exclude newspaper articles"
explain_boost = " * %%boost%% (boost)"
explain_boost_description = "(boost) = %%boost_description%%"
explain_compared = "Relevance in comparison to the relevance of the top result"
explain_coord = " * %%coord%% (adjust for number of matches compared to search)"
explain_disabled = "Explain is deactivated for %%searchClassId%%"
explain_modified_value = "Product of %%relevanceValue%% (relevance value)"
explain_modifier = "with a modifier of %%modifier%%"
explain_relevance = "Record Id: %%recordId%% found with a relevance value of %%relevanceValue%%"
explain_sum = "sum"
Explanation for search = "Explanation for search"
Export = "Export"
Export Favorites = "Export Items"
Export Items = "Export Items"
Expand Down Expand Up @@ -1132,6 +1143,7 @@ relais_success_message = "Request id #%%id%% was created. You will receive a con
Related Author = "Related Author"
Related Items = "Related Items"
Related Subjects = "Related Subjects"
Relevance = "Relevance"
Remove filter = "Remove Filter"
Remove Filters = "Remove Filters"
Remove from Book Bag = "Remove from Book Bag"
Expand Down Expand Up @@ -1374,6 +1386,7 @@ Too Many Email Recipients = "Too Many Email Recipients"
too_many_favorites = "This list is too large to display all at once. Try rearranging your saved items into more lists or limiting using tags."
too_many_new_items = "There are too many new items to display in a single list. Try limiting your search."
too_many_reserves = "There are too many course reserves to display in a single list. Try limiting your search."
Top Result Relevance = "Top Result Relevance"
top_facet_label = "%%label%% within your search."
Topic = "Topic"
Topics = "Topics"
Expand Down
4 changes: 3 additions & 1 deletion module/VuFind/config/module.config.php
Expand Up @@ -466,6 +466,7 @@
'VuFind\Role\PermissionManager' => 'VuFind\Role\PermissionManagerFactory',
'VuFind\Role\PermissionDeniedManager' => 'VuFind\Role\PermissionDeniedManagerFactory',
'VuFind\Search\BackendManager' => 'VuFind\Search\BackendManagerFactory',
'VuFind\Search\Explanation\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory',
'VuFind\Search\FacetCache\PluginManager' => 'VuFind\ServiceManager\AbstractPluginManagerFactory',
'VuFind\Search\Factory\UrlQueryHelperFactory' => 'Laminas\ServiceManager\Factory\InvokableFactory',
'VuFind\Search\History' => 'VuFind\Search\HistoryFactory',
Expand Down Expand Up @@ -656,6 +657,7 @@
'related' => [ /* See VuFind\Related\PluginManager for defaults */ ],
'resolver_driver' => [ /* See VuFind\Resolver\Driver\PluginManager for defaults */ ],
'search_backend' => [ /* See VuFind\Search\BackendRegistry for defaults */ ],
'search_explanation' => [ /* See VuFind\Search\Explanation\PluginManager for defaults */ ],
'search_facetcache' => [ /* See VuFind\Search\FacetCache\PluginManager for defaults */ ],
'search_options' => [ /* See VuFind\Search\Options\PluginManager for defaults */ ],
'search_params' => [ /* See VuFind\Search\Params\PluginManager for defaults */ ],
Expand Down Expand Up @@ -711,7 +713,7 @@
// Define non tab record actions
$nonTabRecordActions = [
'AddComment', 'DeleteComment', 'AddTag', 'DeleteTag', 'Save', 'Email', 'SMS',
'Cite', 'Export', 'RDF', 'Hold', 'Home', 'StorageRetrievalRequest',
'Cite', 'Explain', 'Export', 'RDF', 'Hold', 'Home', 'StorageRetrievalRequest',
'AjaxTab', 'ILLRequest', 'PDF', 'Epub', 'LinkedText', 'Permalink', 'Rating',
];

Expand Down
28 changes: 28 additions & 0 deletions module/VuFind/src/VuFind/Controller/AbstractRecord.php
Expand Up @@ -742,6 +742,34 @@ public function rdfAction()
return $this->exportAction();
}

/**
* Show explanation for why a record was found and how its relevancy is computed
*
* @return mixed
*/
public function explainAction()
{
$record = $this->loadRecord();

$view = $this->createViewModel();
$view->setTemplate('record/explain');
if (!$record->tryMethod('explainEnabled')) {
$view->disabled = true;
return $view;
}

$explanation = $this->serviceLocator
->get(\VuFind\Search\Explanation\PluginManager::class)
->get($record->getSourceIdentifier());

$params = $explanation->getParams();
$params->initFromRequest($this->getRequest()->getQuery());
$explanation->performRequest($record->getUniqueID());

$view->explanation = $explanation;
return $view;
}

/**
* Load the record requested by the user; note that this is not done in the
* init() method since we don't want to perform an expensive search twice
Expand Down
1 change: 1 addition & 0 deletions module/VuFind/src/VuFind/Controller/AbstractSearch.php
Expand Up @@ -364,6 +364,7 @@ protected function getSearchResultsView($setupCallback = null)
// Send both GET and POST variables to search class:
$request = $this->getRequest()->getQuery()->toArray()
+ $this->getRequest()->getPost()->toArray();
$view->request = $request;

$lastView = $this->getSearchMemory()
->retrieveLastSetting($this->searchClassId, 'view');
Expand Down
19 changes: 19 additions & 0 deletions module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
Expand Up @@ -122,6 +122,13 @@ class SolrDefault extends DefaultRecord implements
*/
protected $searchService = null;

/**
* If the explain features is enabled
*
* @var bool
*/
protected $explainEnabled = false;

/**
* Constructor
*
Expand Down Expand Up @@ -154,6 +161,8 @@ public function __construct(
= !isset($mainConfig->Hierarchy->simpleContainerLinks)
? false : $mainConfig->Hierarchy->simpleContainerLinks;

$this->explainEnabled = $searchSettings->Explain->enabled ?? false;

parent::__construct($mainConfig, $recordConfig, $searchSettings);
}

Expand Down Expand Up @@ -329,4 +338,14 @@ public function getWorkKeys()
{
return $this->fields['work_keys_str_mv'] ?? [];
}

/**
* Get if the explain features is enabled.
*
* @return bool
*/
public function explainEnabled()
{
return $this->explainEnabled;
}
}
148 changes: 148 additions & 0 deletions module/VuFind/src/VuFind/Search/Base/Explanation.php
@@ -0,0 +1,148 @@
<?php

/**
* Abstract explanation model.
*
* PHP version 8
*
* Copyright (C) Hebis Verbundzentrale 2023.
*
* 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_Base
* @author Dennis Schrittenlocher <Dennis.Schrittenlocher@outlook.de>
* @author Thomas Wagener <wagener@hebis.uni-frankfurt.de>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org Main Page
*/

namespace VuFind\Search\Base;

use Laminas\Log\LoggerAwareInterface;
use VuFind\Log\LoggerAwareTrait;
use VuFindSearch\Service as SearchService;

/**
* Abstract explanation model.
*
* This abstract class defines the methods for modeling an explanation in VuFind.
*
* @category VuFind
* @package Search_Base
* @author Dennis Schrittenlocher <Dennis.Schrittenlocher@outlook.de>
* @author Thomas Wagener <wagener@hebis.uni-frankfurt.de>
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License
* @link https://vufind.org Main Page
*/
abstract class Explanation implements LoggerAwareInterface
{
use LoggerAwareTrait;

/**
* Configuration
*
* @var \Laminas\Config\Config
*/
protected $config;

/**
* Configuration file to read search settings from
*
* @var string
*/
protected $searchIni = 'searches';
demiankatz marked this conversation as resolved.
Show resolved Hide resolved

/**
* Search Service
*
* @var SearchService
*/
protected $searchService;

/**
* Search string used for query.
*
* @var string
*/
protected $lookfor;

/**
* RecordId of title the explanation is build for.
*
* @var string
*/
protected $recordId;

/**
* Search parameters object
*
* @var \VuFind\Search\Base\Params
*/
protected $params;

/**
* Constructor
*
* @param \VuFind\Search\Base\Params $params Search Parameter
* @param SearchService $searchService Search Service
* @param \VuFind\Config\PluginManager $configLoader Config Loader
*/
public function __construct($params, $searchService, $configLoader)
{
$this->params = $params;
$this->searchService = $searchService;
$this->config = $configLoader->get($this->searchIni);
}

/**
* Performing request and creating explanation.
*
* @param string $recordId Record Id
*
* @throws \VuFindSearch\Backend\Exception\BackendException
* @return void
*/
abstract public function performRequest($recordId);

/**
* Get the search string used for query.
*
* @return string
*/
public function getLookfor()
{
return $this->lookfor;
}

/**
* Get the record id of title the explanation is build for.
demiankatz marked this conversation as resolved.
Show resolved Hide resolved
*
* @return string
*/
public function getRecordId()
{
return $this->recordId;
}

/**
* Get the search parameters object.
*
* @return \VuFind\Search\Base\Params
*/
public function getParams()
{
return $this->params;
}
}