This questions stems from #1246730: Proper way to alter the Solr Document, but it seems more applicable to search_api (as compared to search_api_solr), which is why I'm posting it here.

I've been working on a similar issue where I want to add a custom field to the Solr search index, and my first thought was something similar to what febbraro was thinking. With the apachesolr module, I would just implement hook_apachesolr_update_index() and hook_apachesolr_modify_query() (see here for how I did it in D6 at least), so I was hoping for something that simple.

But to follow along with your point about adding to the index, I've been trying using an implementation of hook_search_api_alter_callback_info(), like so:

/**
 * Implements hook_search_api_alter_callback_info()
 */
function mymodule_search_api_alter_callback_info() {
  $callbacks['mymodule_workflow_state_alter'] = array(
    'name' => t('Workflow State'),
    'description' => t('Adds workflow state information to the index.'),
    'class' => 'MymoduleWorkflowStateAlterSettings',
    'weight' => 100,
  );
  
  return $callbacks;
}

/**
 * @file
 * Search API data alteration callback that adds the workflow state info to the entity.
 */

class MymoduleWorkflowStateAlterSettings extends SearchApiAbstractAlterCallback {

  public function alterItems(array &$items) {
    foreach ($items as $id => &$item) {
      $item->mymodule_workflow_state = $item->workflow;
    }
  }
  
  public function propertyInfo() {
    return array(
      'mymodule_workflow_state' => array(
        'label' => t('Workflow state'),
        'description' => t('The workflow state of the node.'),
        'type' => 'integer',
      ),
    );
  }  
}

The workflow state is already part of the entity object ($item in this context), so it looks like I just need to add it to $items->mymodule_workflow_state. Is that the correct way to do it?

This adds a data alteration at admin/config/search/search_api/index/my_index/workflow, which requires the user to specifically add it. This brings up a couple questions:

  1. Is this the correct way to add workflow state information to the index?
  2. Either way, is there another - or better - hook to implement to add this data to the index so it is
    available for facets and being displayed in search results so that it doesn't require an additional step to add it?

Thanks.

Comments

wonder95’s picture

This seems to be working, but only partially. When I add the field as a facet, it displays correctly in the facet block. However, when I add the field to my view that is based on the Solr index, it displays 0 for every node, even though it shows correct in the facet block. Is there something additional I need to add to get the field value to show correctly?

wonder95’s picture

OK, figured out the problem. Some of the nodes have $item->workflow = 0 (a boolean), which is why they get indexed as 0. I also wanted the name indexed as the state name (a string), so I modified my alterItems method like so:

  public function alterItems(array &$items) {
    foreach ($items as $id => &$item) {
      // We have the sid for the workflow state, but for display purposes,
      // we need to convert it to the state name.
      if ($item->workflow != 0) {
        $state_object = workflow_get_workflow_states_by_sid($item->workflow);      
        // Assign value to search api variable.
        $item->search_api_workflow_state = $state_object->state;
      }
    }
  }

and propertyItems like so:

  public function propertyInfo() {
    return array(
      'search_api_workflow_state' => array(
        'label' => t('Workflow state'),
        'description' => t('The workflow state of the node.'),
        'type' => 'string',
      ),
    );
  } 

After changing the Type value at admin/config/search/search_api/index/solr_index/fields (where solr_index = the machine name of my index), I'm getting the appropriate facets.

However, for some reason, I'm not getting the workflow state field value to show up as a field in the view. It is available to be added, but no results show up at all. There shouldn't be anything else I need to do to get the value to show up, should there?

kpa’s picture

I'm having the same problem as wonder95.

I've added my SearchApiAbstractAlterCallback extender class, and everything is being correctly written into the database for my custom field.

However, when searching on that index through a view, no results show for it. Is there something extra one needs to do for search_api_views custom integration?

Any pointers would be much appreciated.

wonder95’s picture

Status: Active » Closed (fixed)

Per conversation with drunken monkey, I discovered that this approach will only create the facets, not the search results. In order to have the fields show up as search results, you need to follow the approach outlined here by ygerasimov. Doing that, I came up with #1532646: Add workflow state to entity to be available in search_api for facets and fields, which is working perfectly for me.

romanciuc’s picture

Is still this approach by ygerasimov the best way to add custom fileds to the index?
thanks.

merilainen’s picture

I think that approach actually adds a new property, not a field, which can be indexed and displayed. But that doesn't help much with multilingual content (entity translation), because properties don't have a language (which would be a property of a property, I assume).

phponwebsites’s picture

you can add custom fields to search api index with use of hook_entity_property_info_alter().

/**
 * Implements hook_entity_property_info_alter().
 */
function phponwebsites_entity_property_info_alter(&$info) {
  $info['node']['properties']['is_nodeviewcount'] = array(
    'type' => 'integer',
    'label' => t('Node view count'),
    'description' => t("Number of views."),
    'sanitized' => TRUE,
    'getter callback' => 'phponwebsites_get_is_nodeviewcount_callback',
  );
}

/**
 * Implement phponwebsites_get_is_nodeviewcount_callback()
 */
function phponwebsites_get_is_nodeviewcount_callback($item) {
  $count = phponwebsites_get_nodecountviews_nid($item->nid);
  $total = (int) $count;
  return $total;
}

function phponwebsites_get_nodecountviews_nid($nid) {
  $result = db_query("SELECT COUNT(*) as count FROM {nodeviewcount} WHERE nid=:nid", array(':nid' => $nid))->FetchAssoc();
  return $result['count'];
}