How can I combine two entity fields (for example DCAT and Node) into one Search API field to apply a facet on it.
Currently I wrote a custom SearchApiProcessor based on the AddUrl class from SearchAPI. But it seems that the indexation is done as a multiple values field automatically. What do I need to do to make this single valued so multiple values handling isn't active in Views.
namespace Drupal\odp_search\Plugin\search_api\processor;
use Drupal\search_api\Datasource\DatasourceInterface;
use Drupal\search_api\Item\ItemInterface;
use Drupal\search_api\Processor\ProcessorPluginBase;
use Drupal\search_api\Processor\ProcessorProperty;
/**
* Adds the content and dcat title to the indexed data.
*
* @SearchApiProcessor(
* id = "field_title",
* label = @Translation("Title field"),
* description = @Translation("Adds the item's title to the indexed data."),
* stages = {
* "add_properties" = 0,
* },
* locked = true,
* hidden = true,
* )
*/
class FieldTitle extends ProcessorPluginBase {
/**
* {@inheritdoc}
*/
public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) {
$properties = array();
if (!$datasource) {
$definition = array(
'label' => $this->t('Combined title'),
'description' => $this->t('Combined title field for ODP content and DCAT datasets.'),
'type' => 'text',
'processor_id' => $this->getPluginId(),
);
$properties['odp_search_title'] = new ProcessorProperty($definition);
}
return $properties;
}
/**
* {@inheritdoc}
*/
public function addFieldValues(ItemInterface $item) {
$entity = $item->getOriginalObject()->getValue();
$title = NULL;
if ($entity->getEntityType()->id() == 'dcat_dataset') {
$title = $entity->get('name');
}
else if ($entity->getEntityType()->id() == 'node') {
$title = $entity->get('title');
}
if ($title) {
$fields = $this->getFieldsHelper()
->filterForPropertyPath($item->getFields(), NULL, 'odp_search_title');
foreach ($fields as $field) {
if (!$field->getDatasourceId()) {
$field->addValue($title->getString());
}
}
}
}
}
Any suggestions?
PS: I'm trying to index it into SOLR.
Comments
Comment #2
Jeroen_005 commented.
Comment #3
Jeroen_005 commentedComment #4
Jeroen_005 commentedComment #5
drunken monkeyFirst off: I don't think you need a new processor for that, "Aggregated field" is already there to solve exactly this problem. Just add a "General » Aggregated field" to the index and configure it to be a "Union" of the two title fields.
Then, about "single-valued": Since it's not really possible anymore in Drupal 8 (compared to Drupal 7's Entity API module) to distinguish single-valued from multi-valued fields/properties, the Search API treats all fields as multi-valued. So, short answer how to make a Search API field single-valued: you can't.
If there is a specific component (e.g., as you mention it, the Views field handler) that handles the field incorrectly because it thinks it might contain multi-valued data, you'll have to override that component. (Or file a bug report, if it's a general problem – of course, all components should be able to handle single-valued fields sensibly, too (even if they can't know they're single-valued).)
I guess the fact that all fields are multi-valued now will have to be documented, so changing this to a Documentation issue.
Comment #6
ekes commentedI'd assume, from reading the module description, that this is a referenced entity though, and then a field on that. This would need: #2693071: Allow adding indirect fields/properties in aggregate_fields processor ?
Comment #7
Jeroen_005 commentedThanks for the feedback Drunken Monkey.
So if I understand it correctly we could use "Aggregated fields" to accomplish the same result but in the meantime there is no support for "Aggregated fields" in the views module yet? Do you know if there is already an issue for that?
There is only one thing that is a bit strange about this. If you index a field directly from the entity in search api it get indexed as an single valued field. How does Search API accomplished that? For example the description field in this example:
@ekes, Indeed the final intention was to accomplish to create an Facet for a category vocabulary that is both used on DCAT and node entities. If you aggregate those fields the taxonomy name and entity reference gets currently lost in the SOLR index.
Comment #8
drunken monkeyThat's not an accomplishment of the Search API but, apparently, a bug in the Solr module. I'm not familiar with the code but from this and some other bug reports I've read it seems they're trying to guess which fields are single-valued and which are multi-valued – and invariably failing sometimes. It really shouldn't try to do that, but just support both treating fields as single- and multi-valued.
In the Search API itself the fact remains that all fields are multi-valued.
Regarding Views: That should now already be fixed, if I'm not mistaken. I think we resolved that a few weeks back – or there is at least a patch.
@ ekes: Might be true – I'm really not sure anymore at this point.
Comment #9
drupal-son commentedHi,
I would like to combine location fields who have latitude / longitude fields on it to be able to filter by distance.
I can make it work for 1 single field, I just drill down till the coordinates latlon pairs and configure the field type to latitude/longitude.
But now I have a main content type with 3 entity reference fields to a location content type.
The location content type contains the geofield.
I want to combine the 3 and filter by location (distance) on the 3 at a time.
I tried creating a Processor Plugin but wasn't able to accomplish what I needed.
I tried the Union aggregation but that aggregates the whole referenced entity.
I need to drill down to the coordinates latlon on the combined as an indexed field I can use on my index.
Is there a way to drill down on an aggregated field?
What is the best wat to do this?
Thanks.
Comment #10
drunken monkeySeems like the “Aggregated field” provided by Search API would already mostly cover that use case, except that the UI currently doesn’t allow you to specify nested properties as the source of the aggregation (as you say, you can only aggregate the whole entities) – see #2693071: Allow adding indirect fields/properties in aggregate_fields processor. However, you can already get this to work correctly by directly editing the search index’s config (see, e.g., comment #20 in the linked issue for an example). Adding support in the UI for this is, unfortunately, not that simple.
Comment #11
drupal-son commented@drunken-monkey that is an interesting approach ...
I tried it and this was the result:
- I created an aggregated field with my 3 location fields.
- I exported the configuration and changed by hand the 3 fields to point to the nested geofield and nested lat/lon value (just like I see when drilling down a single location field).
- I imported the configuration.
- I reindexed again and cleared caches.
- I tested my query using the search_api_location filter aggregated field value.
- Always get no results no matter how big radius I use.
This is how the aggregated field looks like after manual tweaking:
This is how the search api query location filter looks like:
I was curious how the UI will behave after reimporting the manual tweaked configuration ... It looked like if no fields were selected to be combined. However if I exported the configuration again, the manual changes remain the same, so they are not destroyed on subsequent config exports.
Any other hint or idea?
Comment #12
drunken monkeyAt a glance, this looks like it should have worked.
After reindexing, can you look into the indexed contents of your Solr server and check whether the
field_locations_unionfield (probablylocm_field_locations_unionin Solr) is present, and the contents look as expected?Then you could try to look at the Solr request generated for your search query (using, e.g., the Solr Devel module) and see whether that contains the appropriate filter parameters.