2023-01-20 17:45:01 +00:00
|
|
|
"""Test Qdrant functionality."""
|
2023-05-05 23:46:40 +00:00
|
|
|
from typing import Callable, Optional
|
|
|
|
|
2023-03-02 15:05:14 +00:00
|
|
|
import pytest
|
|
|
|
|
2023-01-20 17:45:01 +00:00
|
|
|
from langchain.docstore.document import Document
|
2023-05-05 23:46:40 +00:00
|
|
|
from langchain.embeddings.base import Embeddings
|
2023-01-20 17:45:01 +00:00
|
|
|
from langchain.vectorstores import Qdrant
|
2023-02-03 06:05:47 +00:00
|
|
|
from tests.integration_tests.vectorstores.fake_embeddings import FakeEmbeddings
|
2023-01-20 17:45:01 +00:00
|
|
|
|
|
|
|
|
2023-03-02 15:05:14 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
["content_payload_key", "metadata_payload_key"],
|
|
|
|
[
|
|
|
|
(Qdrant.CONTENT_KEY, Qdrant.METADATA_KEY),
|
|
|
|
("foo", "bar"),
|
|
|
|
(Qdrant.CONTENT_KEY, "bar"),
|
|
|
|
("foo", Qdrant.METADATA_KEY),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_qdrant(content_payload_key: str, metadata_payload_key: str) -> None:
|
2023-01-20 17:45:01 +00:00
|
|
|
"""Test end to end construction and search."""
|
|
|
|
texts = ["foo", "bar", "baz"]
|
2023-03-02 15:05:14 +00:00
|
|
|
docsearch = Qdrant.from_texts(
|
|
|
|
texts,
|
|
|
|
FakeEmbeddings(),
|
2023-04-04 13:48:21 +00:00
|
|
|
location=":memory:",
|
2023-03-02 15:05:14 +00:00
|
|
|
content_payload_key=content_payload_key,
|
|
|
|
metadata_payload_key=metadata_payload_key,
|
|
|
|
)
|
2023-01-20 17:45:01 +00:00
|
|
|
output = docsearch.similarity_search("foo", k=1)
|
|
|
|
assert output == [Document(page_content="foo")]
|
|
|
|
|
|
|
|
|
2023-05-05 23:46:40 +00:00
|
|
|
def test_qdrant_add_documents() -> None:
|
|
|
|
"""Test end to end construction and search."""
|
|
|
|
texts = ["foo", "bar", "baz"]
|
|
|
|
docsearch: Qdrant = Qdrant.from_texts(texts, FakeEmbeddings(), location=":memory:")
|
|
|
|
|
|
|
|
new_texts = ["foobar", "foobaz"]
|
|
|
|
docsearch.add_documents([Document(page_content=content) for content in new_texts])
|
|
|
|
output = docsearch.similarity_search("foobar", k=1)
|
|
|
|
# FakeEmbeddings return the same query embedding as the first document embedding
|
|
|
|
# computed in `embedding.embed_documents`. Since embed_documents is called twice,
|
|
|
|
# "foo" embedding is the same as "foobar" embedding
|
|
|
|
assert output == [Document(page_content="foobar")] or output == [
|
|
|
|
Document(page_content="foo")
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2023-03-02 15:05:14 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
["content_payload_key", "metadata_payload_key"],
|
|
|
|
[
|
|
|
|
(Qdrant.CONTENT_KEY, Qdrant.METADATA_KEY),
|
|
|
|
("test_content", "test_payload"),
|
|
|
|
(Qdrant.CONTENT_KEY, "payload_test"),
|
|
|
|
("content_test", Qdrant.METADATA_KEY),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_qdrant_with_metadatas(
|
|
|
|
content_payload_key: str, metadata_payload_key: str
|
|
|
|
) -> None:
|
2023-01-20 17:45:01 +00:00
|
|
|
"""Test end to end construction and search."""
|
|
|
|
texts = ["foo", "bar", "baz"]
|
|
|
|
metadatas = [{"page": i} for i in range(len(texts))]
|
|
|
|
docsearch = Qdrant.from_texts(
|
|
|
|
texts,
|
|
|
|
FakeEmbeddings(),
|
|
|
|
metadatas=metadatas,
|
2023-04-04 13:48:21 +00:00
|
|
|
location=":memory:",
|
2023-03-02 15:05:14 +00:00
|
|
|
content_payload_key=content_payload_key,
|
|
|
|
metadata_payload_key=metadata_payload_key,
|
2023-01-20 17:45:01 +00:00
|
|
|
)
|
|
|
|
output = docsearch.similarity_search("foo", k=1)
|
|
|
|
assert output == [Document(page_content="foo", metadata={"page": 0})]
|
|
|
|
|
|
|
|
|
2023-03-15 14:31:39 +00:00
|
|
|
def test_qdrant_similarity_search_filters() -> None:
|
|
|
|
"""Test end to end construction and search."""
|
|
|
|
texts = ["foo", "bar", "baz"]
|
2023-05-09 17:34:11 +00:00
|
|
|
metadatas = [
|
|
|
|
{"page": i, "metadata": {"page": i + 1, "pages": [i + 2, -1]}}
|
|
|
|
for i in range(len(texts))
|
|
|
|
]
|
2023-03-15 14:31:39 +00:00
|
|
|
docsearch = Qdrant.from_texts(
|
|
|
|
texts,
|
|
|
|
FakeEmbeddings(),
|
|
|
|
metadatas=metadatas,
|
2023-04-04 13:48:21 +00:00
|
|
|
location=":memory:",
|
2023-03-15 14:31:39 +00:00
|
|
|
)
|
2023-05-09 17:34:11 +00:00
|
|
|
|
|
|
|
output = docsearch.similarity_search(
|
|
|
|
"foo", k=1, filter={"page": 1, "metadata": {"page": 2, "pages": [3]}}
|
|
|
|
)
|
|
|
|
assert output == [
|
|
|
|
Document(
|
|
|
|
page_content="bar",
|
|
|
|
metadata={"page": 1, "metadata": {"page": 2, "pages": [3, -1]}},
|
|
|
|
)
|
|
|
|
]
|
2023-03-15 14:31:39 +00:00
|
|
|
|
|
|
|
|
2023-03-02 15:05:14 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
["content_payload_key", "metadata_payload_key"],
|
|
|
|
[
|
|
|
|
(Qdrant.CONTENT_KEY, Qdrant.METADATA_KEY),
|
|
|
|
("test_content", "test_payload"),
|
|
|
|
(Qdrant.CONTENT_KEY, "payload_test"),
|
|
|
|
("content_test", Qdrant.METADATA_KEY),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_qdrant_max_marginal_relevance_search(
|
|
|
|
content_payload_key: str, metadata_payload_key: str
|
|
|
|
) -> None:
|
2023-01-20 17:45:01 +00:00
|
|
|
"""Test end to end construction and MRR search."""
|
|
|
|
texts = ["foo", "bar", "baz"]
|
|
|
|
metadatas = [{"page": i} for i in range(len(texts))]
|
|
|
|
docsearch = Qdrant.from_texts(
|
|
|
|
texts,
|
|
|
|
FakeEmbeddings(),
|
|
|
|
metadatas=metadatas,
|
2023-04-04 13:48:21 +00:00
|
|
|
location=":memory:",
|
2023-03-02 15:05:14 +00:00
|
|
|
content_payload_key=content_payload_key,
|
|
|
|
metadata_payload_key=metadata_payload_key,
|
2023-01-20 17:45:01 +00:00
|
|
|
)
|
|
|
|
output = docsearch.max_marginal_relevance_search("foo", k=2, fetch_k=3)
|
|
|
|
assert output == [
|
|
|
|
Document(page_content="foo", metadata={"page": 0}),
|
|
|
|
Document(page_content="bar", metadata={"page": 1}),
|
|
|
|
]
|
2023-05-05 23:46:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
["embeddings", "embedding_function"],
|
|
|
|
[
|
|
|
|
(FakeEmbeddings(), None),
|
|
|
|
(FakeEmbeddings().embed_query, None),
|
|
|
|
(None, FakeEmbeddings().embed_query),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_qdrant_embedding_interface(
|
|
|
|
embeddings: Optional[Embeddings], embedding_function: Optional[Callable]
|
|
|
|
) -> None:
|
|
|
|
from qdrant_client import QdrantClient
|
|
|
|
|
|
|
|
client = QdrantClient(":memory:")
|
|
|
|
collection_name = "test"
|
|
|
|
|
|
|
|
Qdrant(
|
|
|
|
client,
|
|
|
|
collection_name,
|
|
|
|
embeddings=embeddings,
|
|
|
|
embedding_function=embedding_function,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
["embeddings", "embedding_function"],
|
|
|
|
[
|
|
|
|
(FakeEmbeddings(), FakeEmbeddings().embed_query),
|
|
|
|
(None, None),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_qdrant_embedding_interface_raises(
|
|
|
|
embeddings: Optional[Embeddings], embedding_function: Optional[Callable]
|
|
|
|
) -> None:
|
|
|
|
from qdrant_client import QdrantClient
|
|
|
|
|
|
|
|
client = QdrantClient(":memory:")
|
|
|
|
collection_name = "test"
|
|
|
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
Qdrant(
|
|
|
|
client,
|
|
|
|
collection_name,
|
|
|
|
embeddings=embeddings,
|
|
|
|
embedding_function=embedding_function,
|
|
|
|
)
|