ElasticSearch + Haystack en español

Me he vuelto loco configurando el elasticsearch y el haystack para que utilice un analyzer en español (spanish). La ventaja es que de esta forma ignora las palabras “no útiles” en las búsquedas: preposiciones, conjunciones, determinantes y trata mejor los plurales, los géneros…

Primero intentaba configurar a través del fichero elastisearch.yml hasta que he descubierto que el haystack crea su índice sin hacer caso a esos settings. Asi que finalmente lo he conseguido modicando el backend del elasticsearch de haystack:

He creado un fichero que he llamado es_backend.py que hereda del backend original:

from haystack.backends.elasticsearch_backend import ElasticsearchSearchBackend
from haystack.backends.elasticsearch_backend import ElasticsearchSearchEngine

class SpanishESBackend(ElasticsearchSearchBackend):

    DEFAULT_SETTINGS = {
        'settings': {
            "analysis": {
                "analyzer": {
                    "ngram_analyzer": {
                        "type": "custom",
                        "language": "Spanish",
                        "tokenizer": "lowercase",
                        "filter": ["haystack_ngram", "spanish_stop", "spanish_stemmer"]
                    },
                    "edgengram_analyzer": {
                        "type": "custom",
                        "language": "Spanish",
                        "tokenizer": "lowercase",
                        "filter": ["haystack_edgengram", "spanish_stop", "spanish_stemmer"]
                    },
                    "default": {
                        "type": "spanish"
                    }
                },
                "tokenizer": {
                    "haystack_ngram_tokenizer": {
                        "type": "nGram",
                        "min_gram": 3,
                        "max_gram": 15,
                    },
                    "haystack_edgengram_tokenizer": {
                        "type": "edgeNGram",
                        "min_gram": 2,
                        "max_gram": 15,
                        "side": "front"
                    },
                },
                "filter": {
                    "haystack_ngram": {
                        "type": "nGram",
                        "min_gram": 3,
                        "max_gram": 15
                    },
                    "haystack_edgengram": {
                        "type": "edgeNGram",
                        "min_gram": 2,
                        "max_gram": 15
                    },
                    "spanish_stop": {
                      "type":       "stop",
                      "stopwords":  "_spanish_"
                    },
                    "spanish_stemmer": {
                      "type":       "stemmer",
                      "language":   "light_spanish"
                    }
                }
            }
        }
    }

class SpanishElasticsearchSearchEngine(ElasticsearchSearchEngine):
    backend = SpanishESBackend

Y en el settings del proyecto donde se configura haystack:

HAYSTACK_CONNECTIONS = {
 'default': {
 'ENGINE': 'app.es_backend.SpanishElasticsearchSearchEngine',
 'URL': 'http://127.0.0.1:9200/',
 'INDEX_NAME': 'haystack-test',
 },
}

Después hay que reconstruir el índice y listos:

./manage.py rebuild_index

Para demostrar que efectivamente funciona podemos primero comprobar que el índice está bien creado:

curl -XGET 'http://localhost:9200/haystack-test/_settings?pretty=true'

Tiene que devolver un objeto json con los misma configuración que hemos definido arriba

Ahora analizamos un texto en castellano y debe quedarse sólo con las palabras principales:

curl -XGET 'localhost:9200/haystack-test/_analyze?text=el+perro+que+ladró+a+los+gatos&pretty=true'
{
 "tokens" : [ {
 "token" : "perr",
 "start_offset" : 3,
 "end_offset" : 8,
 "type" : "<ALPHANUM>",
 "position" : 2
 }, {
 "token" : "ladr",
 "start_offset" : 13,
 "end_offset" : 18,
 "type" : "<ALPHANUM>",
 "position" : 4
 }, {
 "token" : "gat",
 "start_offset" : 25,
 "end_offset" : 30,
 "type" : "<ALPHANUM>",
 "position" : 7
 } ]
}

Vemos que ha quitado las palabras el, que, a, los y además ha eliminado los sufijos del plural, género…

Finalmente probamos lo mismo en inglés para demostrar que no entiende nada:

curl -XGET 'localhost:9200/haystack-test/_analyze?text=the+dog+which+barked+at+the+cats&pretty=true'
{
 "tokens" : [ {
 "token" : "the",
 "start_offset" : 0,
 "end_offset" : 3,
 "type" : "<ALPHANUM>",
 "position" : 1
 }, {
 "token" : "dog",
 "start_offset" : 4,
 "end_offset" : 7,
 "type" : "<ALPHANUM>",
 "position" : 2
 }, {
 "token" : "which",
 "start_offset" : 8,
 "end_offset" : 13,
 "type" : "<ALPHANUM>",
 "position" : 3
 }, {
 "token" : "barked",
 "start_offset" : 14,
 "end_offset" : 20,
 "type" : "<ALPHANUM>",
 "position" : 4
 }, {
 "token" : "at",
 "start_offset" : 21,
 "end_offset" : 23,
 "type" : "<ALPHANUM>",
 "position" : 5
 }, {
 "token" : "the",
 "start_offset" : 24,
 "end_offset" : 27,
 "type" : "<ALPHANUM>",
 "position" : 6
 }, {
 "token" : "cats",
 "start_offset" : 28,
 "end_offset" : 32,
 "type" : "<ALPHANUM>",
 "position" : 7
 } ]
}

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *