Векторный поиск с помощью PGVector занимает больше времени
Я использую PGVector в Django для создания векторного поиска. Время поиска совпадающей строки составляет несколько миллисекунд, код, который я использую для этого, выглядит так
embedding=self.get_input_embedding(inputText)
output=(
table.objects.annotate(
distance=CosineDistance("embedding",embedding)
)
.order_by(CosineDistance("embedding",embedding))
.filter(distance__lt=1-threshold)[:2]
)
Выходная переменная имеет тип класса QuerySet. Теперь, чтобы получить из нее значение, я использую код
for neigh in output:
print(neigh.Link)
Теперь этот блок занимает более 3 секунд. В чем может быть причина этого?
Ниже приведен простой воспроизводимый код.
Models.py
from django.db import models
from django.db import migrations
from pgvector.django import VectorField, VectorExtension
class Migration(migrations.Migration):
operations = [VectorExtension()]
class Question_match(models.Model):
Title = models.TextField("Text")
Link = models.TextField("Text")
Questions = models.TextField("Text")
Answers = models.TextField("Text")
embedding = VectorField(dimensions=1536)
class Meta:
db_table = "generated_question"
pipelines/retrieving_matches.py
from openai import OpenAI
from pgvector.django import CosineDistance
class EmbeddingMatch(object):
def __init__(self):
self.client = OpenAI()
def get_input_embedding(self, input_query):
return self.client.embeddings.create(input=([input_query]),
model="text-embedding-3-small").data[0].embedding
def predict(self, inputText,table,threshold=0.7,nresponse: int=2):
embedding=self.get_input_embedding(inputText)
records=[]
output=(
table.objects.annotate(
distance=CosineDistance("embedding",embedding)
)
.order_by(CosineDistance("embedding",embedding))
.filter(distance__lt=1-threshold)[:2]
)
records.extend(
[
(neighbour.Title,neighbour.Link,neighbour.Questions,1-neighbour.distance)
for neighbour in output
]
)
return records
apps.py
from question_answer.pipelines.retrieving_matches import EmbeddingMatch
class DirectMap(AppConfig):
question_match = EmbeddingMatch()
views.py
from .models import Question_match
class get_question(APIView):
def __init__(self):
pass
def post(self, request, *args, **kwargs):
inputs = json.loads(request.body)
# question is the query we want to get the answers for
query = inputs.get("question")
qwerty = DirectMap.question_match.predict(query, Question_match)
.
.
.
.
Я также попытался использовать SQL-запрос, используя соединения django, и все равно время ответа было высоким и занимало около 4-5 секунд.
query = """SELECT "Link"
FROM generated_question
ORDER BY embedding <=> %s::vector
LIMIT 5"""
with connection.cursor() as cursor:
cursor.execute(query, [vector_str])
result = cursor.fetchall()
Django QuerySets являются lazy и оцениваются как documented
(query)
ничего не делает, а запрос выполняется при итерации