Semantisch Suche mittels Python & FastAPI
Im ersten Artikel bin ich bereits darauf eingegangen wie ihr eine REST-API in Python erstellen können. In diesem Artikel geht es darum, wie ihr diese für eine semantische Suche verwenden könnt.
Was ist semantisch Suche?
Bei der lexikalischen Suche werden eure Texte (z.B. Blog-Artikel auf eurer Website) nach den passenden Keywords durchsucht. Problem hierbei ist, dass Dokumente die nicht exakt die gleiche Schreibweise enthalten nicht gefunden werden. Such ihr z.B. nach öl-profit.de, so wird eine Seite die über ÖL Profit nicht gefunden, da die Schreibweise nicht identisch ist.
Dieses Problem umgeht die semantisch Suche. Dabei werden Texte und Suchanfragen in einen Vektorraum abgebildet so dass ähnliche Wörter und Texte nah sind im Vektorraum. Auf die genaue Schreibweise kommt es dabei nicht mehr an, ebenfalls werden Synonyme und verwandte Begriffe dabei erkannt. Eine Suchanfrage wird dabei ebenfalls erst in so einen Vektor umgewandelt, bevor dann im Vektorraum nach passenden Dokumenten gesucht wird.
Semantische Suche mittels Python
Die semantische Suche ist in Python sehr einfach zu realisieren dank des sentence-transformers Projekts. Installiert dazu zuerst das Projekt:
1 |
pip install sentence-transformers |
Anschließend könnt ihr eine sematische Suche wie folgt erzielen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
from sentence_transformers import SentenceTransformer, util import torch embedder = SentenceTransformer('all-MiniLM-L6-v2') # Corpus with example sentences corpus = ['A man is eating food.', 'A man is eating a piece of bread.', 'The girl is carrying a baby.', 'A man is riding a horse.', 'A woman is playing violin.', 'Two men pushed carts through the woods.', 'A man is riding a white horse on an enclosed ground.', 'A monkey is playing drums.', 'A cheetah is running behind its prey.' ] corpus_embeddings = embedder.encode(corpus, convert_to_tensor=True) # Query sentences: queries = ['A man is eating pasta.', 'Someone in a gorilla costume is playing a set of drums.', 'A cheetah chases prey on across a field.'] # Find the closest 5 sentences of the corpus for each query sentence based on cosine similarity top_k = min(5, len(corpus)) for query in queries: query_embedding = embedder.encode(query, convert_to_tensor=True) # We use cosine-similarity and torch.topk to find the highest 5 scores cos_scores = util.os_sim(query_embedding, corpus_embeddings)[0] top_results = torch.topk(cos_scores, k=top_k) print("\n\n======================\n\n") print("Query:", query) print("\nTop 5 most similar sentences in corpus:") for score, idx in zip(top_results[0], top_results[1]): print(corpus[idx], "(Score: {:.4f})".format(score)) |
Semantische Suche als REST-API
Abschließend können wir dies als REST-API mittels FastAPI verpacken.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
from typing import Optional from fastapi import FastAPI from sentence_transformers import SentenceTransformer, util import torch embedder = SentenceTransformer('all-MiniLM-L6-v2') # Corpus with example sentences corpus = ['A man is eating food.', 'A man is eating a piece of bread.', 'The girl is carrying a baby.', 'A man is riding a horse.', 'A woman is playing violin.', 'Two men pushed carts through the woods.', 'A man is riding a white horse on an enclosed ground.', 'A monkey is playing drums.', 'A cheetah is running behind its prey.' ] corpus_embeddings = embedder.encode(corpus, convert_to_tensor=True) app = FastAPI() @app.get("/suche/{query}") def read_item(query: str): query_embedding = embedder.encode(query, convert_to_tensor=True) cos_scores = util.pytorch_cos_sim(query_embedding, corpus_embeddings)[0] top_results = torch.topk(cos_scores, k=5) return top_results |
Jede Suchanfrage wandeln wir zuerst den den Vektor um (query_embedding). Anschließend wird dieser Vektor mit allen Einträgen im Corpus verglichen und die top-5 Ergebnisse werden zurück geliefert. Fertig.
Autor: Nils Reimers