You are here

protected function SearchApiDbService::indexItem in Search API Database Search 7

Indexes a single item on the specified index.

Used as a helper method in indexItems().

Parameters

SearchApiIndex $index: The index for which the item is being indexed.

$id: The item's ID.

array $item: The extracted fields of the item.

Throws

Exception Any encountered database (or other) exceptions are passed on, out of this method.

1 call to SearchApiDbService::indexItem()
SearchApiDbService::indexItems in ./service.inc
Indexes the specified items.

File

./service.inc, line 850
Contains SearchApiDbService.

Class

SearchApiDbService
Indexes and searches items using the database.

Code

protected function indexItem(SearchApiIndex $index, $id, array $item) {
  $fields = $this
    ->getFieldInfo($index);
  $fields_updated = FALSE;
  $txn = $this->connection
    ->startTransaction('search_api_indexing');
  try {
    $inserts = array();
    $text_inserts = array();
    foreach ($item as $name => $field) {

      // Sometimes index changes are not triggering the update hooks
      // correctly. Therefore, to avoid DB errors, we re-check the tables
      // here before indexing.
      if (empty($fields[$name]['table']) && !$fields_updated) {
        unset($this->options['indexes'][$index->machine_name][$name]);
        $this
          ->fieldsUpdated($index);
        $fields_updated = TRUE;
        $fields = $this->options['indexes'][$index->machine_name];
      }
      if (empty($fields[$name]['table'])) {
        watchdog('search_api_db', "Unknown field !field: please check (and re-save) the index's fields settings.", array(
          '!field' => $name,
        ), WATCHDOG_WARNING);
        continue;
      }
      $table = $fields[$name]['table'];
      $boost = $fields[$name]['boost'];
      $this->connection
        ->delete($table)
        ->condition('item_id', $id)
        ->execute();

      // Don't index null values
      if ($field['value'] === NULL) {
        continue;
      }
      $type = $field['type'];
      $value = $this
        ->convert($field['value'], $type, $field['original_type'], $index);
      if (search_api_is_text_type($type, array(
        'text',
        'tokens',
      ))) {
        $words = array();
        foreach ($value as $token) {

          // Taken from core search to reflect less importance of words later
          // in the text.
          // Focus is a decaying value in terms of the amount of unique words
          // up to this point. From 100 words and more, it decays, to e.g. 0.5
          // at 500 words and 0.3 at 1000 words.
          $focus = min(1, 0.01 + 3.5 / (2 + count($words) * 0.015));
          $token_value =& $token['value'];
          $token_value = trim(preg_replace('/[\\pZ\\pC]+/u', ' ', $token_value));
          if (is_numeric($token_value)) {
            $token_value = ltrim($token_value, '-0');
          }
          elseif (drupal_strlen($token_value) < $this->options['min_chars']) {
            continue;
          }
          $token_value = drupal_strtolower($token_value);
          $token['score'] *= $focus;
          if (!isset($words[$token_value])) {
            $words[$token_value] = $token;
          }
          else {
            $words[$token_value]['score'] += $token['score'];
          }
          unset($token_value);
        }
        if ($words) {
          $field_name = self::getTextFieldName($name);
          foreach ($words as $word) {
            $score = round($word['score'] * $boost * self::SCORE_MULTIPLIER);

            // Take care that the score doesn't exceed the maximum value for
            // the database column (2^32-1).
            $score = min((int) $score, 4294967295);
            $text_inserts[$table][] = array(
              'item_id' => $id,
              'field_name' => $field_name,
              'word' => $word['value'],
              'score' => $score,
            );
          }
        }
      }
      elseif (search_api_is_list_type($type)) {
        $values = array();
        if (is_array($value)) {
          foreach ($value as $v) {
            if (isset($v)) {
              $values["{$v}"] = TRUE;
            }
          }
          $values = array_keys($values);
        }
        elseif (isset($value)) {
          $values[] = $value;
        }
        if ($values) {
          $insert = $this->connection
            ->insert($table)
            ->fields(array(
            'item_id',
            $fields[$name]['column'],
          ));
          foreach ($values as $v) {
            $insert
              ->values(array(
              'item_id' => $id,
              $fields[$name]['column'] => $v,
            ));
          }
          $insert
            ->execute();
        }
      }
      elseif (isset($value)) {
        $inserts[$table][$fields[$name]['column']] = $value;
      }
    }
    foreach ($inserts as $table => $data) {
      $this->connection
        ->insert($table)
        ->fields(array_merge($data, array(
        'item_id' => $id,
      )))
        ->execute();
    }
    foreach ($text_inserts as $table => $data) {
      $query = $this->connection
        ->insert($table)
        ->fields(array(
        'item_id',
        'field_name',
        'word',
        'score',
      ));
      foreach ($data as $row) {
        $query
          ->values($row);
      }
      $query
        ->execute();
    }
  } catch (Exception $e) {
    $txn
      ->rollback();
    throw $e;
  }
}