Skip to content

Commit

Permalink
Merge pull request #52 from netgen/NGSTACK-489-extra-solr-fields
Browse files Browse the repository at this point in the history
NGSTACK-489 Extra solr fields
  • Loading branch information
pspanja authored Feb 23, 2021
2 parents fe068cf + dae56dd commit 2fff55b
Show file tree
Hide file tree
Showing 18 changed files with 746 additions and 9 deletions.
56 changes: 56 additions & 0 deletions docs/reference/extra_fields.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Extra fields from Solr
======================

This feature allows you to extract additionally indexed Solr fields from each SearchHit in SearchResult. For example, you can index some fields from children content on the parent content and then get those fields during search (eg. children count).

.. note::

This feature is available only with the Solr search engine.

1. Usage
~~~~~~~~

In order for this functionality to work, you have to use overridden `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query` or `Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery` queries and use it's property `extraFields` to provide a list of additional fields that you want to extract from the Solr document. Those fields, if exist, and their values will appear in the `extraFields` property of each `SearchHit` object contained in the `SearchResult.`

2. Example
~~~~~~~~~~

Example of a content field mapper:

.. code-block:: php
public function mapFields(SPIContent $content)
{
return [
new Field(
'extra_field_example',
5,
new IntegerField()
),
];
}
Search example:

.. code-block:: php
/** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query $query **/
$query = new Query();
$query->extraFields = [
'extra_field_example_i',
];
/** @var \Netgen\EzPlatformSiteApi\API\FindService $findService **/
$searchResult = $findService->findContent($query);
/** @var \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchHit **/
foreach ($searchResult->searchHits as $searchHit) {
var_dump($searchHit->extraFields);
}
This will output the following data:

.. code-block:: shell
array(1) { ["extra_field_example_i"]=> int(5) }
1 change: 1 addition & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ Reference
random_sort
subdocuments
spellcheck_suggestions
extra_fields

.. include:: /reference/map.rst.inc
16 changes: 16 additions & 0 deletions lib/API/Values/Content/Search/LocationQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Netgen\EzPlatformSearchExtra\API\Values\Content\Search;

use eZ\Publish\API\Repository\Values\Content\LocationQuery as BaseLocationQuery;

class LocationQuery extends BaseLocationQuery
{
/**
* List of additional fields that should be
* extracted from the Solr document for each hit.
*
* @var string[]
*/
public $extraFields;
}
16 changes: 16 additions & 0 deletions lib/API/Values/Content/Search/Query.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Netgen\EzPlatformSearchExtra\API\Values\Content\Search;

use eZ\Publish\API\Repository\Values\Content\Query as BaseQuery;

class Query extends BaseQuery
{
/**
* List of additional fields that should be
* extracted from the Solr document for each hit.
*
* @var string[]
*/
public $extraFields;
}
15 changes: 15 additions & 0 deletions lib/API/Values/Content/Search/SearchHit.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Netgen\EzPlatformSearchExtra\API\Values\Content\Search;

use eZ\Publish\API\Repository\Values\Content\Search\SearchHit as BaseSearchHit;

class SearchHit extends BaseSearchHit
{
/**
* Additional fields from Solr document.
*
* @var array
*/
public $extraFields;
}
49 changes: 44 additions & 5 deletions lib/Core/Search/Solr/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,58 @@

namespace Netgen\EzPlatformSearchExtra\Core\Search\Solr;

use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalAnd;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalNot;
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
use EzSystems\EzPlatformSolrSearchEngine\DocumentMapper;
use EzSystems\EzPlatformSolrSearchEngine\Handler as BaseHandler;
use eZ\Publish\Core\Base\Exceptions\NotFoundException;

class Handler extends BaseHandler
{
public function findContent(Query $query, array $languageFilter = array())
{
$query = clone $query;
$query->filter = $query->filter ?: new Criterion\MatchAll();
$query->query = $query->query ?: new Criterion\MatchAll();

$this->coreFilter->apply(
$query,
$languageFilter,
DocumentMapper::DOCUMENT_TYPE_IDENTIFIER_CONTENT
);

return $this->resultExtractor->extract(
$this->gateway->findContent($query, $languageFilter),
$query->facetBuilders,
$query
);
}

public function findLocations(LocationQuery $query, array $languageFilter = array())
{
$query = clone $query;
$query->query = $query->query ?: new Criterion\MatchAll();

$this->coreFilter->apply(
$query,
$languageFilter,
DocumentMapper::DOCUMENT_TYPE_IDENTIFIER_LOCATION
);

return $this->resultExtractor->extract(
$this->gateway->findLocations($query, $languageFilter),
$query->facetBuilders,
$query
);
}

protected function deleteAllItemsWithoutAdditionalLocation($locationId)
{
$query = $this->prepareQuery();
$query->filter = new LogicalAnd([
$query->filter = new Criterion\LogicalAnd([
$this->allItemsWithinLocation($locationId),
new LogicalNot($this->allItemsWithinLocationWithAdditionalLocation($locationId)),
new Criterion\LogicalNot($this->allItemsWithinLocationWithAdditionalLocation($locationId)),
]);

$contentIds = $this->extractContentIds(
Expand All @@ -30,7 +69,7 @@ protected function deleteAllItemsWithoutAdditionalLocation($locationId)
protected function updateAllElementsWithAdditionalLocation($locationId)
{
$query = $this->prepareQuery();
$query->filter = new LogicalAnd([
$query->filter = new Criterion\LogicalAnd([
$this->allItemsWithinLocation($locationId),
$this->allItemsWithinLocationWithAdditionalLocation($locationId),
]);
Expand Down
43 changes: 42 additions & 1 deletion lib/Core/Search/Solr/ResultExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

use EzSystems\EzPlatformSolrSearchEngine\ResultExtractor as BaseResultExtractor;
use Netgen\EzPlatformSearchExtra\Core\Search\Solr\API\FacetBuilder\RawFacetBuilder;
use eZ\Publish\API\Repository\Values\Content\Query;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\Query as ExtraQuery;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\LocationQuery as ExtraLocationQuery;
use Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit;

/**
* This DocumentMapper implementation adds support for handling RawFacetBuilders.
Expand All @@ -12,10 +16,23 @@
*/
abstract class ResultExtractor Extends BaseResultExtractor
{
public function extract($data, array $facetBuilders = [])
public function extract($data, array $facetBuilders = [], ?Query $query = null)
{
$searchResult = $this->extractSearchResult($data, $facetBuilders);

foreach ($searchResult->searchHits as $key => $searchHit) {
$searchResult->searchHits[$key] = new SearchHit(get_object_vars($searchHit));
$searchResult->searchHits[$key]->extraFields = [];

if (($query instanceof ExtraQuery || $query instanceof ExtraLocationQuery) && is_array($query->extraFields)) {
$searchResult->searchHits[$key]->extraFields = $this->extractExtraFields(
$data,
$searchResult->searchHits[$key],
$query->extraFields
);
}
}

if (!isset($data->facets) || $data->facets->count === 0) {
return $searchResult;
}
Expand Down Expand Up @@ -57,4 +74,28 @@ function ($facetBuilder) {
}
);
}

/**
* @param mixed $data
* @param \Netgen\EzPlatformSearchExtra\API\Values\Content\Search\SearchHit $searchHit
* @param string[] $extraFields
*
* @return array
*/
private function extractExtraFields($data, SearchHit $searchHit, $extraFields)
{
$extractedExtraFields = [];
foreach ($data->response->docs as $doc) {
if ($doc->document_type_id === 'content' && $doc->content_id_id == $searchHit->valueObject->id
|| $doc->document_type_id === 'location' && $doc->location_id == $searchHit->valueObject->id) {
foreach ($extraFields as $extraField) {
if (property_exists($doc, $extraField)) {
$extractedExtraFields[$extraField] = $doc->{$extraField};
}
}
}
}

return $extractedExtraFields;
}
}
2 changes: 2 additions & 0 deletions phpunit-integration-legacy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<exclude>tests/lib/Integration/API/IsFieldEmptyCriterionTest.php</exclude>
<exclude>tests/lib/Integration/API/SubdocumentFieldSortClauseTest.php</exclude>
<exclude>tests/lib/Integration/API/SubdocumentQueryCriterionTest.php</exclude>
<exclude>tests/lib/Integration/API/FulltextSpellcheckCriterionTest.php</exclude>
<exclude>tests/lib/Integration/API/ExtraFieldsTest.php</exclude>
<exclude>tests/lib/Integration/Solr/RawFacetDomainTest.php</exclude>
<exclude>tests/lib/Integration/Solr/RawFacetTest.php</exclude>
</testsuite>
Expand Down
Loading

0 comments on commit 2fff55b

Please sign in to comment.