Cómo eliminar archivos del índice de SOLR tras ser remplazado en nodos de Drupal 7

Author Top
enzo

En Drupal si se tienen habilitadas las revisiones en los tipos de contenido se mantendrán todos sus archivos viejos en el servidor (asociados con revisiones anteriores de los nodos), por lo que reemplazar un archivo sin duda es una tarea difícil.

Además a pesar de que no tiene estén las revisiones habilitadas, si se intenta quitar y añadir de nuevo archivo para el nodo con el mismo nombre para actualizarlo, esta acción no es del todo exitosa, porque al existir un archivo con ese nombre en el sistema, este se mantiene en el servidor y para evitar una duplicación del nombre Drupal agrega sufijos al archivo como "_0", "_1" etc a las nuevas versiones de este archivo.

En términos del render del  nodo esto no es un problema, pero en términos de indexación dentro de SOLR si que lo es, porque se indexarán todos esos archivos. De tal forma que en vez de obtener un registro para una coincidencia, es posible obtener N registros, donde N es el número de veces que se ha sobre escrito el mismo archivo.

Entonces, para resolver este comportamiento molesto te mostraré una solución para eliminar un archivo del índice de SOLR cuando este archivo se elimine de un nodo. esta solución utiliza el módulo Entity API Entidad por lo que debe ser añadido como una dependencia en el archivo .info del módulo.

/**
 * Implements hook_node_update().
 */
function MYMODULE_node_update($node) {

  // Array of content types to act on.
  if (in_array($node->type, array('article', 'blog_post'))) {
    $wrapper = entity_metadata_wrapper('node', $node);
    $original_wrapper = entity_metadata_wrapper('node', $node->original);

    // Array of file fields to act on.
    foreach (array('field_public_files', 'field_private_files') as $field) {
      if (!isset($original_wrapper->{$field})) {
        continue;
      }
      $current_files = array();
      $original_files = array();

      // Get files that were attached to the original node (before update).
      foreach ($original_wrapper->{$field}->value() as $file) {
        $original_files[] = $file['fid'];
      }
      // Stop if there were no files previously attached.
      if (empty($original_files)) {
        continue;
      }

      // Get files currently attached to the node (after update).
      foreach ($wrapper->{$field}->value() as $file) {
        $current_files[] = $file['fid'];
      }

      // Delete files that were in the original node but were removed during this update
      $deleted_files = array_diff($original_files, $current_files);
      if(!empty($deleted_files)) {
       $env_id = apachesolr_default_environment();
       $solr = apachesolr_get_solr($env_id);
       foreach ($deleted_files as $fid) {
         $file_id = apachesolr_document_id($fid, 'file') . '-' . $node->nid;

         // Remove file document from SOLR index, re-index is not required,
         $solr->deleteByQuery("id:$file_id");
       }
      }
    }
      $deleted_files = array_diff($original_files, $current_files);
      if(!empty($deleted_files)) {

    }
  }
}

El código anterior reacciona cuando un nodo se actualiza para los tipos de contenido article y blog y campos field_public_filesfield_private_files , utilizando la función entity_metadata_wrapper podemos determinar la información del nodo antes y después de la actualización.

Después de calcular si algun(os) archivo(s) fueron borrados del nodo la lógica para eliminar el archivo del índice de SOLR se aplica. Veamos este código en detalle

$env_id = apachesolr_default_environment();
$solr = apachesolr_get_solr($env_id);
foreach ($deleted_files as $fid) {
 $file_id = apachesolr_document_id($fid, 'file') . '-' . $node->nid;

 // Remove file document from SOLR index, re-index is not required,
 $solr->deleteByQuery("id:$file_id");
}

En primer lugar, una instancia de SOLR se declara. En mi ejemplo utilize la instancia de SOLR por defecto, si se tiene más de una instancia de SOLR es necesario cambiar la lógica para utilizar la instancia adecuada.

Usando la función apachesolr_document_id el SOLR ID se calculando utilizando el fid y el tipo 'file', además proporcionamos una relación específica con el nodo que se esta actualizando, porque en algunas configuraciones de Drupal un archivo podría estar asociado a varios nodos.

Por último, utilizando el método deleteByQuery para solicitar la eliminación del índice, esta eliminación se aplica de inmediato, no se requiere re-indexar SOLR .

Espero que está entrada de blog haya sido de su agrado.