En este tutorial sobre el motor de búsquedas Elasticsearch vamos a ver cómo implementar diferentes políticas que nos permitirán crear buscadores que vayan más allá de la simple correspondencia léxica.
Índice de contenidos
1. Introducción
Cuando nos enfrentamos a un problema de búsquedas relacionado con el lenguaje natural estamos lidiando con un problema de interpretación de las entradas que se reciben a la hora de realizar la búsqueda. Este proceso de interpretación puede enfocarse desde múltiples puntos de vista:
- Normalización de términos.
- Reducir los términos a su lexema.
- Sinónimos.
- …
En el presente tutorial vamos a realizar una serie de aproximaciones sucesivas sobre esta problemática con Elasticsearch para ver cómo podemos ir mejorando un sistema de búsquedas de manera iterativa e incremental.
2. Entorno
El tutorial está escrito usando el siguiente entorno:
- Hardware: portátil MacBook Pro Retina 15′ (2.7 Ghz Intel Core I7, 16GB DDR3)
- Sistema operativo: Mac OS Sierra 10.12.5
- Elasticsearch 5.4
3. Aproximaciones
3.1. Punto de partida
Disponemos de un índice en Elasticsearch que almacena informes con un texto relativo a la intervención que realizó un veterinario y, sobre esos documentos, queremos realizar búsquedas por términos relacionados, por ejemplo perros.
PUT interventions/report/1 { "description": "El caballo presenta un estado perfecto de salud." } PUT interventions/report/2 { "description": "Se ha detectado enrojecimiento y sequedad en los ojos del border collie." } PUT interventions/report/3 { "description": "El bull terrier tiene síntomas de hiperactividad." } PUT interventions/report/4 { "description": "El gato de origen alemán tiene perdida de pelo." } PUT interventions/report/5 { "description": "Se trata de un dogo alemán con caracter violento." } POST interventions/_search { "query": { "match_phrase": { "description": "perro" } } }
Como podemos comprobar, al realizar una búsqueda por «perro» no obtenemos ningún resultado, puesto que la coincidencia exacta de valores no se da en ningún caso, tampoco obtenemos ningún valor relacionado.
3.2. Aproximación basada en sinónimos
La primera aproximación que podemos realizar sobre el problema consiste en definir un conjunto de sinónimos que haga que el buscador nos devuelva correspondencias entre términos como sinónimos.
DELETE interventions PUT interventions { "mappings": { "report": { "properties": { "description": { "type": "string", "analyzer": "syn_report_description" } } } }, "settings": { "analysis": { "analyzer": { "syn_report_description": { "tokenizer": "standard", "filter": ["animal_synonym"] } }, "filter": { "animal_synonym": { "type": "synonym", "synonyms": ["perro, chucho, border collie, bull terrier,dogo alemán, labrador, pinscher miniatura"] } } } } }
Para el mismo conjunto de datos podemos replantear la búsqueda que realizabamos en el punto anterior.
POST interventions/_search { "query": { "match_phrase": { "description": "perro" } } }
Gracias a al filtro que hemos establecido el resultado será el esperado y aparecerán aquellas coincidencias con los sinónimos definidos. Sin embargo, aparece un comportamiento que puede resultar no adecuado dependiendo de la precisión que se requiera.
Por ejemplo:
POST interventions/_search { "query": { "match_phrase": { "description": "miniatura" } } } POST interventions/_search { "query": { "match_phrase": { "description": "dogo terrier" } } }
Este comportamiento se produce debido a la forma en la que Elasticsearch procesa la información. A muy alto nivel, podemos decir que Elasticsearch, a través de los analizadores, se encarga de generar tokens por separado para cada término que encuentra de acuerdo a un conjunto de reglas.
En este ejemplo concreto, establecemos un analizador basado, por un lado, en un generador de tokens standard y por el otro lado un filtro (que también procesará tokens) ad-hoc basado en sinónimos.
Así, sobre nuestro ejemplo podemos ver que, al establecer el texto «border collie» nuestro analizador va a generar dos conjuntos de tokens «border» y «collie» y, con posterioridad, aplicará los conjuntos de sinónimos dejando los conjuntos como «perro, chucho, border, bull, dogo, labrador, pinscher» y «collie, terrier, alemán, miniatura». Y son estos conjuntos de tokens los que se tendrán en cuenta a la hora de realizar la búsqueda posterior, pudiendo generar valores correctos («border collie» o «bull terrier») y valores incorrectos («labrador alemán», «chucho terrier»).
3.3. Aproximación basada en sinónimos mejorada
Una posible mejora sobre la solución basada en sinónimos pasa por considerar algunos términos compuestos como un único token, de esta manera eliminamos la posibilidad del cruce de términos indebido que veíamos en el punto anterior.
Esto puede conseguirse simplemente estableciendo un generador de tokens distinto a nivel de nuestro filtro de sinónimos, en concreto el tipo keyword. Sin embargo, estableciendo este tipo de tokenizador perdemos la potencia de la que disponíamos a través de los sinónimos.
Es en este punto donde entra el filtro keep, que nos permitirá mantener ciertos términos dentro de las búsquedas retomando esa potencia perdida por el tokenizador.
Todo esto lo estableceremos como un subcampo dentro del campo descripción para que, a la hora de realizar búsquedas, podamos aumentar la prioridad de ciertas correspondencias frente a otras.
PUT interventions { "mappings": { "report": { "properties": { "description": { "type": "string", "analyzer": "spanish", "fields": { "entities": { "type": "string", "analyzer": "interventions_report_description" } } } } } }, "settings": { "analysis": { "analyzer": { "interventions_report_description": { "tokenizer": "standard", "filter": ["4_shingle","animals_synonym", "keep_animals"] } }, "filter": { "4_shingle": { "type": "shingle", "max_shingle_size": 4, "min_shingle_size": 2, "output_unigrams": true }, "animals_synonym": { "type": "synonym", "tokenizer": "keyword", "synonyms": ["perro, chucho, border collie, bull terrier, dogo alemán, labrador, pinscher miniatura"] }, "keep_animals": { "type": "keep", "keep_words": ["perro", "chucho", "border collie", "bull terrier", "dogo alemán", "labrador", "pinscher miniatura"] } } } } }
O de manera manual, mediante la sintaxis de Solr:
PUT interventions { "mappings": { "report": { "properties": { "description": { "type": "string", "analyzer": "interventions_report_description" } } } }, "settings": { "analysis": { "analyzer": { "interventions_report_description": { "tokenizer": "standard", "filter": ["animals_synonym", "autophrase_synomnym"] } }, "filter": { "animals_synonym": { "type": "synonym", "tokenizer": "keyword", "synonyms": ["perro, chucho, border_collie, bull_terrier, dogo_aleman, labrador, pinscher_miniatura"] }, "autophrase_synomnym": { "type": "synonym", "synonyms": ["border collie => border_collie", "bull terrier => bull_terrier", "dogo aleman => dogo_aleman", "pinscher miniatura => pinscher_miniatura"] } } } } } POST interventions/_search { "query": { "bool": { "should": [ {"match": { "text.entities": "border collie" }}, {"match": { "text": "border collie" }}] } } } POST interventions/_search { "query": { "bool": { "should": [ {"match": { "description.entities": { "query": "border collie", "boost": 10 } }}, {"match_phrase": { "description": { "query": "border collie", "boost": 5 } }}, {"match": { "description": "border collie" }} ] } } }
3.4. Aproximación basada en taxonomías y vocabularios controlados
Si queremos realizar una aproximación más cercana al lenguaje natural necesitamos centrar nuestros esfuerzos en las taxonomías y los vocabularios controlados.
Las taxonomías son clasificaciones jerárquicas de cosas, por ejemplo la categoría taxonómica: taxones o grupos en que se clasifican los seres vivos: Dominio > Reino > Filo > Clase > Orden > Familia > Género > Especie
Un vocabulario controlado es una extensión de una taxonomía que tiene en cuenta sinónimos. Ejemplos de vocabularios controlados son: Tesauros, encabezamientos de materias u ontologías.
En concreto, un tesauro es un instrumento de control terminológico que traduce a un lenguaje sistémico o documental el lenguaje natural empleado en los documentos y por los usuarios. Consiste en un vocabulario controlado y dinámico de términos relacionados semántica y jerárquicamente, que se aplica a un campo específico del conocimiento.
Algunos ejemplos de tesauros pueden ser:
- Tesauro de Propiedad Industrial
- AGROVOC
- Sears
- MeSH
- Biblioteca del congreso de los Estados Unidos
- Tesauro de la UNESCO
Los términos que conforman el tesauro se interrelacionan entre ellos bajo tres modalidades de relación:
- Relaciones jerárquicas: establecen subdivisiones que generalmente reflejan estructuras de TODO/Parte. Hiperónimos e hipónimos.
- Los hiperónimo: aquel término que puede ser utilizado para referirse a la realidad nombrada por un término más específico.
- Los hipónimos: palabra que posee todos los rasgos semánticos, o semas, de otra más general —su hiperónimo— pero que en su definición añade otras características semánticas que la diferencias de ésta.
- Relaciones de equivalencia: controlan la sinonimia, homonimia, antonimia y polisemia entre los términos.
- Relaciones asociativas: mejoran las estrategias de recuperación y ayudan a reducir la poli-jerarquía entre los términos.
DELETE interventions PUT interventions { "mappings": { "report": { "properties": { "description": { "type": "string", "analyzer": "interventions_report_description" } } } }, "settings": { "analysis": { "analyzer": { "interventions_report_description": { "tokenizer": "standard", "filter": ["autophrase_synonym", "vocabulary"] } }, "filter": { "vocabulary": { "type": "synonym", "synonyms": [ "cefalea => cefalea, dolor_de_cabeza, dolor", "migraña => migraña, dolor_de_cabeza, dolor", "jaqueca => jaqueca, dolor_de_cabeza, dolor", "hemicránea => hemicránea, dolor_de_cabeza, dolor", "apendicitis => apendicitis, dolor_abdominal, dolor", "mala_digestión => mala_digestión, dolor_abdominal, dolor", "gastritis => gastritis, dolor_abdominal, dolor", "intestino_irritable => intestino_irritable, dolor_abdominal, dolor", "bursitis => bursitis, dolor_articular, dolor", "condromalacia => condromalacia, dolor_articular, dolor", "osteoartritis => osteoartritis, dolor_articular, dolor", "osteomielitis => osteomielitis, dolor_articular, dolor", "tendinitis => tendinitis, dolor_articular, dolor" ] }, "autophrase_synonym": { "type": "synonym", "synonyms": ["dolor de cabeza => dolor_de_cabeza", "dolor abdominal => dolor_abdominal", "mala digestión => mala_digestión", "intestino irritable => intestino_irritable", "dolor articular => dolor_articular"] } } } } } PUT interventions/report/1 { "description": "El paciente referia cefalea." } PUT interventions/report/2 { "description": "Se presenta jaqueca durante el ejercicio." } PUT interventions/report/3 { "description": "Dice que tuvo una mala digestión." } PUT interventions/report/4 { "description": "El sobreesfuerzo produjo una tendinitis." } PUT interventions/report/5 { "description": "Tiene condromalacia." } POST interventions/_search { "query": { "match_phrase": { "description": "dolor" } } }
4. Conclusiones
Como hemos visto, con Elastisearch podemos implementar múltiples políticas de análisis enfocadas en las búsquedas permitiéndonos así responder a un amplio abanico de necesidades.
Sinónimos, vocabularios o taxonomías son distintos enfoques para resolver un mismo problema, afrontar la tarea (nada trivial) de intentar comprender qué información es la que realmente el consumidor quiere recibir en base a un «lenguaje natural».
Queda en nuestra mano, como profesionales del software, razonar cuál de las soluciones es la que mejor se adapta a las necesidades a cubrir siempre optando por la más sencilla.
Usted realmente hace que parezca muy fácil junto con su presentación pero I en encontrar esto materia para ser en realidad una cosa lo que Creo Lo haría nunca entender. Se siente un poco demasiado complicado y extremadamente vasto para mí. Estoy Echando un vistazo adelante su subsiguiente publicar , I¡¦ll intentaré obtener el hang de ello!