Search API Solr en Drupal 8

Bases prácticas para encontrar lo buscado
Agustín Gómez / @TuWebO
#DrupalCampEs

Agustín Gómez

Desarrollador y Site-builder

drupal.org/u/TuWebO

Vamos a hablar de:

  1. Breve historia de Search API y Search API Solr
  2. Elementos de las páginas de búsqueda
  3. La búsqueda
  4. Configuración de Search API Solr
  5. Configuración de Solr
  6. Ejemplo / Demo

Historia

Battleplan

"Contrib Search maintainers are committed to make Drupal 8 kick ass with Search API."

drunken monkey's picture

Thomas Seidl
@drunken monkey

Nick_vh's picture

Nick Veenhof
@nick_vh

Time line

26 Abr 2017 - Official stable release Search API - 8.x-1.0

2017 Search API in Drupal 8 is about to be stable!
2016 Add support for extract to Connector API
Integra distintas "configuraciones" en Search API Solr
Battleplan for Search & Solr in Drupal 8
Acquia invierte esfuerzo para unificar el módulo Search API
2013 Kicking off the Search API D8 port (again) in Szeged
¡Cogemos fuerzas de nuevo!
(Solr) Search in Drupal 8
Search del core, Query classes, Index logic...
Change workflow plugin system
Unify processors and data alterations, datasources, service classes into proper plugins
2012 Solr Wizardry at Dev Days Barcelona 2012
Colaboración entre mantenedores

Algunas Mejoras

  • Plugins para integrar muchos de los componentes
  • "Multidioma" integrado en Search API
  • Processors más poderosos
  • Solarium
  • Tests

¡Contribuye!

Empieza por la Documentación

https://www.drupal.org/docs/7/modules/search-api https://www.drupal.org/docs/8/modules/search-api

Facets, filtros, sorts, rangos, resaltado...

Módulos de Drupal

https://www.drupal.org/docs/8/modules/search-api/extension-modules

Server backends Otros módulos
Solr search Flag Search API
Multilingual Solr search Search API attachments
Database search Search API Location
Elasticsearch Connector Search API sorts
Search API Algolia Autocomplete
Facets
Search API Exclude Entity
Search pages
Multi-index searches

Y si... ¿sólo tenemos este elemento?

Devolver todos los documentos relevantes y nada más

Search API + Search API Solr + Solr lo hacen muy bien "Out of the box".

Pequeñas diferencias en su configuración importan.

¿Qué almacenamos y cómo para ofrecer buenos resutlados?

Busca la letra "N"

¿En qué filas sale y cuátas veces?

A

A E

C K N

A R F O

V P G X D

R E A F K O

N V K V O A Z

N P H T A N X U

X D F H P T Z A N

F A X T D N H U P Z

Solr indexa así

Lo que tú haces con las letras él lo hace con las palabras (más o menos). Tiene campos con "super poderes".

"¿Hay huevos fritos con papas?"

🡓
"huev frit pap" "huev frit patat"

Configuración de Search API Solr

En Drupal

Muy resumido

Tierras de items, data sources, campos, processors...

En detalle

Primero instalación

  1. Debes tener instalado un servidor Solr
  2. Módulo Search del core, desinstalado
  3. Módulo Search API Solr instalado

Usa composer. Recuerda que Solarium es una dependencia ahora.

Configuración

  1. Crear el servidor y el índice
  2. Añadir campos al índice
  3. Crear vista para buscar y mostrar resultados

El índice decide qué información (campos) se va a guardar y cómo (tipo de dato)

El "servidor" es el que hace la tarea de almacenar la información y buscarla

Creación de servidor e índice

Servidor -> Backend

Backend -> Connector

Drupal -> Solr

Comprobamos archivos

Índice -> Datasources

Podemos añadir varios Datasources

Índice -> Server

Opciones del índice

Valora la seguridad antes de elegir la opción

Índice -> Campos

Campos añadidos

Podemos añadir dos campos para una misma propiedad

Comprobar - Módulo Devel

Activa el módulo Devel y comprueba como se mapean los campos.

Índice -> Procesadores

Por lo general los procesadores añaden "propiedades" o alteran valores de campos en distintas etapas del proceso.

Indexamos

Search API Solr incluye el módulo search_api_solr_defaults, donde parte de la configuración la tienes hecha, incluyendo una vista por defecto.

Añadimos vista

Configuramos vista

No cacheamos. Añadimos filtro expuesto de "Full text search" y lo configuramos para que no admita menos de dos caracteres y seleccionamos los campos sobre los que queremos buscar. Ordenamos por relevancia DESC (podemos añadir después fecha DESC por ejemplo), configuramos permisos de acceso, filtramos por tipo de contenido y por estado del contenido (publicado o no). Añadimos resumen de resultados en la cabecera y texto cuando no hay resultados.

Comprobamos

Yeahhh!!!!

Demo

#fail

Configuración de Solr

Archivos de configuración de Solr

Todo el código es experimental, sólo con el propósito de dar un ejemplo. Sólo se está usando para estas diapositivas.

Muy resumido

Queremos crear un campo en Solr con "super poderes" que procese el texto que guarda y que también lo procese cuando lo busca

Añadir sinónimos, eliminar tildes y palabras comunes...

Vista de archivos

Fundamental: README.txt
search_api_solr/README.txt
Copia los archivos de configuración
search_api_solr/solr-conf/VERSION_NUMBER.x
stopwords_es.txt
Añade stopwords
synonyms_es.xml
Añade sinónimos
mapping-ISOLatin1Accent.txt
Añade las entradas correspondientes
schema_extra_types.xml
Configura campos para español o tu caso de uso (o usa Search API Multilingual Solr Search)
schema_extra_fields.xml
Implementa los campos que has configurado

Pasos

  1. Crear un nuevo tipo de campo en el esquema de Solr
  2. Añadir sinónimos y stopwords, para que nuestro campo los use a la hora de analizar
  3. Ver cómo se comporta el campo (por interfaz de Solr)
  4. Dar de alta el campo en Drupal mediante plugins para que lo reconozca

Nuevo tipo de campo en solr

schema_extra_types.xml

Cada filter y tokenizer que ves, es parecido a los procesadores de Search API, por eso no debemos activar muchos procesadores en Drupal, Solr ya procesa el texto de la forma que queramos nosotros.


<fieldType name="text_tapas_bar" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
        <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
        <filter class="solr.SynonymFilterFactory" synonyms="lang/synonyms_es.txt" ignoreCase="true" expand="true"/>
        <filter class="solr.StopFilterFactory" words="lang/stopwords_tildes_added_es.txt" format="snowball" ignoreCase="true"/>
        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" catenateWords="1" catenateNumbers="1" catenateAll="0" protected="protwords.txt" preserveOriginal="1"/>
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.SpanishLightStemFilterFactory"/>
        <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
    </analyzer>
    </analyzer>
    <analyzer type="query">
        <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>
        <tokenizer class="solr.WhitespaceTokenizerFactory"/>
        <!-- Read https://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.SynonymFilterFactory -->
        <!-- <filter class="solr.SynonymFilterFactory" synonyms="lang/synonyms_es.txt" ignoreCase="true" expand="true"/> -->
        <filter class="solr.StopFilterFactory" words="lang/stopwords_tildes_added_es.txt" format="snowball" ignoreCase="true"/>
        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" splitOnCaseChange="1" splitOnNumerics="1" catenateWords="0" catenateNumbers="0" catenateAll="0" protected="protwords.txt" preserveOriginal="1"/>
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.SpanishLightStemFilterFactory"/>
        <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
    </analyzer>
</fieldType>
						

Crear campos dinámicos asociados a ese tipo

schema_extra_fields.xml


<dynamicField name="tbars_*" type="text_tapas_bar" indexed="true" stored="true" multiValued="false" termVectors="true"/>
<dynamicField name="tbarm_*" type="text_tapas_bar" indexed="true" stored="true" multiValued="true" termVectors="true"/>
					

Estos campos dinámicos van a ser reconocidos por Search API Solr, siempre y cuando tengan la nomenclatura adecuada como vimos antes.

Recargamos el core y comprobamos si aparece nuestro campo

Pequeño análisis de nuestro campo

Puedes comprobar directamente en Solr cómo se va a indexar y a buscar tu campo.
¡Es muy útil!

Demo

¡Ahora si!

Implementación en Drupal

La hacemos a través de plugins

Crear backend plugin de Search API Solr que reconozca nuestro tipo.

Crear un plugin data_type para que Drupal pueda operar con él.

Extra: Ejemplo de processor plugin que crea un campo (propiedad) para indexar.

Backend

Probablemente esto no es lo que quieras hacer en producción, pero como ejemplo vale para ver los elementos implicados


namespace Drupal\tapas_bar_solr\Plugin\search_api\backend;
use Drupal\search_api_solr\Plugin\search_api\backend\SearchApiSolrBackend;
/**
* Experimental Apache Solr backend for search api.
*
* @SearchApiBackend(
*   id = "tapas_bar_solr_backend",
*   label = @Translation("Experimental Tapas Bar Solr backend"),
*   description = @Translation("Index items using a Custom Solr backend.")
* )
*/
class TapasBarSolrServer extends SearchApiSolrBackend {
function supportsDataType($type) {
return parent::supportsDataType($type) | $type == 'text_tapas_bar';
  }
}

Extendemos el DataTypePluginBase


namespace Drupal\tapas_bar_solr\Plugin\search_api\data_type;
use Drupal\search_api\DataType\DataTypePluginBase;
/**
 *
 * @SearchApiDataType(
 *   id = "text_tapas_bar",
 *   label = @Translation("FullText Tapas Bar"),
 *   description = @Translation("A text field which takes in account Spanish tapas bar language"),
 *   fallback_type = "text",
 *   prefix = "tbar",
 * )
 */
class TapasBarDataType extends DataTypePluginBase {
}

Comprobamos que es reconocido


Plugin que añade un campo booleano, que puede ser indexado y reconocido por views

Existen funciones para comprobar si el índice es soportado... no están incluidas.

namespace Drupal\tapas_bar_solr\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 an experimental property to index.
 *
 * hidden = true | Won't show on Processors Tab
 * locked = true | If it shows, it will be "disabled"
 *
 * @SearchApiProcessor(
 *   id = "tapas_add_discount",
 *   label = @Translation("Adds experimental boolean field"),
 *   description = @Translation("Adds experimental boolean field as if it were a discount (tapas bar)."),
 *   stages = {
 *     "add_properties" = 0,
 *   },
 *   locked = true,
 *   hidden = false,
 * )
 */
class AddTapasDiscount extends ProcessorPluginBase {

  /**
   * {@inheritdoc}
   */
  public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) {
    $properties = [];

    if (!$datasource) {
      $definition = [
        'label' => $this->t('Tapas Bar - Add discount fields'),
        'description' => $this->t('Adds a discount boolean field'),
        'type' => 'boolean',
        'processor_id' => $this->getPluginId(),
      ];
      $properties['tapas_discount_field'] = new ProcessorProperty($definition);
    }

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public function addFieldValues(ItemInterface $item) {
    $fields = $this->getFieldsHelper()
      ->filterForPropertyPath($item->getFields(), NULL, 'tapas_discount_field');
    foreach ($fields as $field) {
      if (!$field->getDatasourceId()) {
        // Let's map it with an integer and see how it behaves...
        $field->addValue(rand(0,1) == 1);
      }
    }
  }}

Comprobamos

Referencias

Trabajando con Drupal, Search API y Solr (algo desactualizado pero con mucha información válida)
http://metadrop.net/articulo/trabajando-drupal-search-api-solr
Apache Solr Reference Guide
https://cwiki.apache.org/confluence/display/solr/Apache+Solr+Reference+Guide
Solr resources
https://lucene.apache.org/solr/resources.html#documentation
Solarium project
http://www.solarium-project.org
Explore the benefits / drawbacks of integrating with the Solarium library (Drupal issue )
Lucene vs Solr
http://www.lucenetutorial.com/lucene-vs-solr.html
What the fq? A short summary of Solr query fields.
https://www.triquanta.nl/blog/what-fq-short-summary-solr-query-fields
Analyzers
https://cwiki.apache.org/confluence/display/solr/Analyzers
Tokenizers
https://cwiki.apache.org/confluence/display/solr/About+Tokenizers
Filters
https://cwiki.apache.org/confluence/display/solr/About+Filters
What is term vector in Lucene
http://makble.com/what-is-term-vector-in-lucene

Otras Referencias

Búsquedas "Full Text"
https://en.wikipedia.org/wiki/Full-text_search
http://stackoverflow.com/questions/224714/what-is-full-text-search-vs-like

¡Muchas gracias!

drupal.org/u/tuwebo

https://tuwebo.github.io/drupal8-search-api-drupalcampes-2017

¡A todos los voluntarios!

¡A la Organización!

¡A la Asociación Española de Drupal!

¡A los patrocinadores!

¡A todos vosotros!