FEATURE: Allow range queries for elasticsearch

Allow "raw" configuration and support "range" type.

Also prevent adding boosts if no search term was submitted which can be
boosted.

Resolves: #119
This commit is contained in:
Daniel Siepmann 2018-03-06 16:34:59 +01:00
parent 74e5f6d432
commit 88f301f228
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
3 changed files with 107 additions and 8 deletions

View file

@ -121,6 +121,10 @@ class QueryFactory
return;
}
if (trim($searchRequest->getSearchTerm()) === '') {
return;
}
$boostQueryParts = [];
foreach ($fields as $fieldName => $boostValue) {
@ -238,6 +242,18 @@ class QueryFactory
}
}
if (isset($config['raw'])) {
$filter = array_merge($config['raw'], $filter);
}
if ($config['type'] === 'range') {
return [
'range' => [
$config['field'] => $filter,
],
];
}
return [$config['field'] => $filter];
}

View file

@ -119,20 +119,48 @@ E.g. you submit a filter in form of:
.. code-block:: html
<f:form.textfield property="filter.distance.location.lat" value="51.168098" />
<f:form.textfield property="filter.distance.location.lon" value="6.381384" />
<f:form.textfield property="filter.distance.distance" value="100km" />
<f:comment>
Due to TYPO3 7.x fluid limitations, we build this input ourself.
No longer necessary in 8 and above
</f:comment>
<select name="tx_searchcore_search[searchRequest][filter][month][from]" class="_control" >
<option value="">Month</option>
<f:for each="{searchResult.facets.month.options}" as="month">
<f:if condition="{month.count}">
<option
value="{month.displayName -> f:format.date(format: 'Y-m')}"
{f:if(condition: '{searchRequest.filter.month.from} == {month.displayName -> f:format.date(format: \'Y-m\')}', then: 'selected="true"')}
>{month.displayName -> f:format.date(format: '%B %Y')}</option>
</f:if>
</f:for>
</select>
<select name="tx_searchcore_search[searchRequest][filter][month][to]" class="_control" >
<option value="">Month</option>
<f:for each="{searchResult.facets.month.options}" as="month">
<f:if condition="{month.count}">
<option
value="{month.displayName -> f:format.date(format: 'Y-m')}"
{f:if(condition: '{searchRequest.filter.month.from} == {month.displayName -> f:format.date(format: \'Y-m\')}', then: 'selected="true"')}
>{month.displayName -> f:format.date(format: '%B %Y')}</option>
</f:if>
</f:for>
</select>
This will create a ``distance`` filter with subproperties. To make this filter actually work, you
can add the following TypoScript, which will be added to the filter::
mapping {
filter {
distance {
field = geo_distance
month {
type = range
field = released
raw {
format = yyyy-MM
}
fields {
distance = distance
location = location
gte = from
lte = to
}
}
}
@ -143,9 +171,12 @@ in elasticsearch. In above example they do match, but you can also use different
On the left hand side is the elasticsearch field name, on the right side the one submitted as a
filter.
The ``field``, in above example ``geo_distance``, will be used as the elasticsearch field for
The ``field``, in above example ``released``, will be used as the elasticsearch field for
filtering. This way you can use arbitrary filter names and map them to existing elasticsearch fields.
Everything that is configured inside ``raw`` is passed, as is, to search service, e.g.
elasticsearch.
.. _fields:
fields

View file

@ -86,6 +86,58 @@ class QueryFactoryTest extends AbstractUnitTestCase
);
}
/**
* @test
*/
public function rangeFilterIsAddedToQuery()
{
$this->configureConfigurationMockWithDefault();
$this->configuration->expects($this->any())
->method('getIfExists')
->will($this->returnCallback(function ($configName) {
if ($configName === 'searching.mapping.filter.month') {
return [
'type' => 'range',
'field' => 'released',
'raw' => [
'format' => 'yyyy-MM',
],
'fields' => [
'gte' => 'from',
'lte' => 'to',
],
];
}
return [];
}));
$searchRequest = new SearchRequest('SearchWord');
$searchRequest->setFilter([
'month' => [
'from' => '2016-03',
'to' => '2017-11',
],
]);
$query = $this->subject->create($searchRequest);
$this->assertSame(
[
[
'range' => [
'released' => [
'format' => 'yyyy-MM',
'gte' => '2016-03',
'lte' => '2017-11',
],
],
]
],
$query->toArray()['query']['bool']['filter'],
'Filter was not added to query.'
);
}
/**
* @test
*/