Introduction rapide à la recherche en texte intégral avec ElasticSearch

Haut de persistance

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS

1. Vue d'ensemble

Recherche en texte intégral et effectue des recherches linguistiques sur les documents. Il comprend des mots ou des phrases simples ou multiples et renvoie des documents qui correspondent à la condition de recherche.

ElasticSearch est un moteur de recherche basé sur Apache Lucene, une bibliothèque de logiciels de recherche d'informations gratuits et open source. Il fournit un moteur de recherche distribué en texte intégral avec une interface Web HTTP et des documents JSON sans schéma.

Cet article examine l'API REST ElasticSearch et montre les opérations de base à l'aide de requêtes HTTP uniquement.

2. Configuration

Pour installer ElasticSearch sur votre machine, veuillez vous référer au guide d'installation officiel.

L'API RESTfull s'exécute sur le port 9200. Testons si elle fonctionne correctement à l'aide de la commande curl suivante:

curl -XGET '//localhost:9200/'

Si vous observez la réponse suivante, l'instance s'exécute correctement:

{ "name": "NaIlQWU", "cluster_name": "elasticsearch", "cluster_uuid": "enkBkWqqQrS0vp_NXmjQMQ", "version": { "number": "5.1.2", "build_hash": "c8c4c16", "build_date": "2017-01-11T20:18:39.146Z", "build_snapshot": false, "lucene_version": "6.3.0" }, "tagline": "You Know, for Search" }

3. Indexation des documents

ElasticSearch est orienté document. Il stocke et indexe les documents. L'indexation crée ou met à jour des documents. Après l'indexation, vous pouvez rechercher, trier et filtrer des documents complets, et non des lignes de données en colonnes. Il s'agit d'une manière fondamentalement différente de penser les données et c'est l'une des raisons pour lesquelles ElasticSearch peut effectuer une recherche complexe en texte intégral.

Les documents sont représentés sous forme d'objets JSON. La sérialisation JSON est prise en charge par la plupart des langages de programmation et est devenue le format standard utilisé par le mouvement NoSQL. Il est simple, concis et facile à lire.

Nous allons utiliser les entrées aléatoires suivantes pour effectuer notre recherche en texte intégral:

{ "title": "He went", "random_text": "He went such dare good fact. The small own seven saved man age." } { "title": "He oppose", "random_text": "He oppose at thrown desire of no. \ Announcing impression unaffected day his are unreserved indulgence." } { "title": "Repulsive questions", "random_text": "Repulsive questions contented him few extensive supported." } { "title": "Old education", "random_text": "Old education him departure any arranging one prevailed." }

Avant de pouvoir indexer un document, nous devons décider où le stocker. Il est possible d'avoir plusieurs index, qui à leur tour contiennent plusieurs types. Ces types contiennent plusieurs documents et chaque document comporte plusieurs champs.

Nous allons stocker nos documents en utilisant le schéma suivant:

text : le nom de l'index.

article : le nom du type.

id : l'ID de cet exemple particulier de saisie de texte.

Pour ajouter un document, nous allons exécuter la commande suivante:

curl -XPUT 'localhost:9200/text/article/1?pretty' -H 'Content-Type: application/json' -d ' { "title": "He went", "random_text": "He went such dare good fact. The small own seven saved man age." }'

Ici, nous utilisons id = 1 , nous pouvons ajouter d'autres entrées en utilisant la même commande et un id incrémenté.

4. Récupération de documents

Après avoir ajouté tous nos documents, nous pouvons vérifier combien de documents, à l'aide de la commande suivante, nous avons dans le cluster:

curl -XGET '//localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' 

De plus, nous pouvons obtenir un document en utilisant son identifiant avec la commande suivante:

curl -XGET 'localhost:9200/text/article/1?pretty' 

Et nous devrions obtenir la réponse suivante à partir de la recherche élastique:

{ "_index": "text", "_type": "article", "_id": "1", "_version": 1, "found": true, "_source": { "title": "He went", "random_text": "He went such dare good fact. The small own seven saved man age." } }

Comme nous pouvons le voir, cette réponse correspond à l'entrée ajoutée en utilisant l'id 1.

5. Interrogation de documents

OK, effectuons une recherche en texte intégral avec la commande suivante:

curl -XGET 'localhost:9200/text/article/_search?pretty' -H 'Content-Type: application/json' -d ' { "query": { "match": { "random_text": "him departure" } } }'

Et nous obtenons le résultat suivant:

{ "took": 32, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 2, "max_score": 1.4513469, "hits": [ { "_index": "text", "_type": "article", "_id": "4", "_score": 1.4513469, "_source": { "title": "Old education", "random_text": "Old education him departure any arranging one prevailed." } }, { "_index": "text", "_type": "article", "_id": "3", "_score": 0.28582606, "_source": { "title": "Repulsive questions", "random_text": "Repulsive questions contented him few extensive supported." } } ] } }

Comme nous pouvons le voir, nous cherchons «lui départ» et nous obtenons deux résultats avec des scores différents. Le premier résultat est évident car le texte contient la recherche effectuée et comme nous pouvons le voir, nous avons le score de 1,4513469 .

Le deuxième résultat est récupéré car le document cible contient le mot «lui».

By default, ElasticSearch sorts matching results by their relevance score, that is, by how well each document matches the query. Note, that the score of the second result is small relative to the first hit, indicating lower relevance.

6. Fuzzy Search

Fuzzy matching treats two words that are “fuzzily” similar as if they were the same word. First, we need to define what we mean by fuzziness.

Elasticsearch supports a maximum edit distance, specified with the fuzziness parameter, of 2. The fuzziness parameter can be set to AUTO, which results in the following maximum edit distances:

  • 0 for strings of one or two characters
  • 1 for strings of three, four, or five characters
  • 2 for strings of more than five characters

you may find that an edit distance of 2 returns results that don’t appear to be related.

You may get better results, and better performance, with a maximum fuzziness of 1. Distance refers to the Levenshtein distance that is a string metric for measuring the difference between two sequences. Informally, the Levenshtein distance between two words is the minimum number of single-character edits.

OK let's perform our search with fuzziness:

curl -XGET 'localhost:9200/text/article/_search?pretty' -H 'Content-Type: application/json' -d' { "query": { "match": { "random_text": { "query": "him departure", "fuzziness": "2" } } } }'

And here's the result:

{ "took": 88, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 1.5834423, "hits": [ { "_index": "text", "_type": "article", "_id": "4", "_score": 1.4513469, "_source": { "title": "Old education", "random_text": "Old education him departure any arranging one prevailed." } }, { "_index": "text", "_type": "article", "_id": "2", "_score": 0.41093433, "_source": { "title": "He oppose", "random_text": "He oppose at thrown desire of no. \ Announcing impression unaffected day his are unreserved indulgence." } }, { "_index": "text", "_type": "article", "_id": "3", "_score": 0.2876821, "_source": { "title": "Repulsive questions", "random_text": "Repulsive questions contented him few extensive supported." } }, { "_index": "text", "_type": "article", "_id": "1", "_score": 0.0, "_source": { "title": "He went", "random_text": "He went such dare good fact. The small own seven saved man age." } } ] } }'

As we can see the fuzziness give us more results.

We need to use fuzziness carefully because it tends to retrieve results that look unrelated.

7. Conclusion

In this quick tutorial we focused on indexing documents and querying Elasticsearch for full-text search, directly via it's REST API.

Bien sûr, nous avons des API disponibles pour plusieurs langages de programmation lorsque nous en avons besoin - mais l'API est toujours assez pratique et indépendante du langage.

Fond de persistance

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS