pgvector-haystack 0.5.0__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/CHANGELOG.md +15 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/PKG-INFO +1 -1
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/examples/embedding_retrieval.py +1 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/examples/hybrid_retrieval.py +1 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/pyproject.toml +6 -4
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/src/haystack_integrations/components/retrievers/pgvector/embedding_retriever.py +5 -1
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/src/haystack_integrations/components/retrievers/pgvector/keyword_retriever.py +5 -1
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/src/haystack_integrations/document_stores/pgvector/document_store.py +2 -2
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/conftest.py +1 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/test_document_store.py +2 -1
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/test_embedding_retrieval.py +2 -1
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/test_filters.py +4 -3
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/test_keyword_retrieval.py +1 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/test_retrievers.py +50 -1
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/.gitignore +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/LICENSE.txt +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/README.md +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/pydoc/config.yml +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/src/haystack_integrations/components/retrievers/pgvector/__init__.py +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/src/haystack_integrations/document_stores/pgvector/__init__.py +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/src/haystack_integrations/document_stores/pgvector/filters.py +0 -0
- {pgvector_haystack-0.5.0 → pgvector_haystack-1.0.0}/tests/__init__.py +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [unreleased]
|
|
4
|
+
|
|
5
|
+
### 🚀 Features
|
|
6
|
+
|
|
7
|
+
- Add filter_policy to pgvector integration (#820)
|
|
8
|
+
|
|
9
|
+
### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- `PgVector` - Fallback to default filter policy when deserializing retrievers without the init parameter (#900)
|
|
12
|
+
|
|
13
|
+
### ⚙️ Miscellaneous Tasks
|
|
14
|
+
|
|
15
|
+
- Retry tests to reduce flakyness (#836)
|
|
16
|
+
- Update ruff invocation to include check parameter (#853)
|
|
17
|
+
|
|
3
18
|
## [integrations/pgvector-v0.4.0] - 2024-06-20
|
|
4
19
|
|
|
5
20
|
### 🚀 Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: pgvector-haystack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: An integration of pgvector (vector search extension for Postgres) with Haystack
|
|
5
5
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations
|
|
6
6
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/pgvector/README.md
|
|
@@ -17,6 +17,7 @@ from haystack.components.converters import MarkdownToDocument
|
|
|
17
17
|
from haystack.components.embedders import SentenceTransformersDocumentEmbedder, SentenceTransformersTextEmbedder
|
|
18
18
|
from haystack.components.preprocessors import DocumentSplitter
|
|
19
19
|
from haystack.components.writers import DocumentWriter
|
|
20
|
+
|
|
20
21
|
from haystack_integrations.components.retrievers.pgvector import PgvectorEmbeddingRetriever
|
|
21
22
|
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
22
23
|
|
|
@@ -18,6 +18,7 @@ from haystack.components.embedders import SentenceTransformersDocumentEmbedder,
|
|
|
18
18
|
from haystack.components.joiners import DocumentJoiner
|
|
19
19
|
from haystack.components.preprocessors import DocumentSplitter
|
|
20
20
|
from haystack.components.writers import DocumentWriter
|
|
21
|
+
|
|
21
22
|
from haystack_integrations.components.retrievers.pgvector import PgvectorEmbeddingRetriever, PgvectorKeywordRetriever
|
|
22
23
|
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
23
24
|
|
|
@@ -50,10 +50,12 @@ dependencies = [
|
|
|
50
50
|
"haystack-pydoc-tools",
|
|
51
51
|
]
|
|
52
52
|
[tool.hatch.envs.default.scripts]
|
|
53
|
-
test = "pytest
|
|
54
|
-
test-cov = "coverage run -m pytest
|
|
53
|
+
test = "pytest {args:tests}"
|
|
54
|
+
test-cov = "coverage run -m pytest {args:tests}"
|
|
55
|
+
test-cov-retry = "test-cov --reruns 3 --reruns-delay 30 -x"
|
|
55
56
|
cov-report = ["- coverage combine", "coverage report"]
|
|
56
57
|
cov = ["test-cov", "cov-report"]
|
|
58
|
+
cov-retry = ["test-cov-retry", "cov-report"]
|
|
57
59
|
docs = ["pydoc-markdown pydoc/config.yml"]
|
|
58
60
|
|
|
59
61
|
[[tool.hatch.envs.all.matrix]]
|
|
@@ -64,8 +66,8 @@ detached = true
|
|
|
64
66
|
dependencies = ["black>=23.1.0", "mypy>=1.0.0", "ruff>=0.0.243"]
|
|
65
67
|
[tool.hatch.envs.lint.scripts]
|
|
66
68
|
typing = "mypy --install-types --non-interactive --explicit-package-bases {args:src/ tests}"
|
|
67
|
-
style = ["ruff check {args:.}", "black --check --diff {args:.}"]
|
|
68
|
-
fmt = ["black {args:.}", "ruff --fix {args:.}", "style"]
|
|
69
|
+
style = ["ruff check {args:. --exclude tests/, examples/}", "black --check --diff {args:.}"]
|
|
70
|
+
fmt = ["black {args:.}", "ruff --fix {args:. --exclude tests/, examples/}", "style"]
|
|
69
71
|
all = ["style", "typing"]
|
|
70
72
|
|
|
71
73
|
[tool.black]
|
|
@@ -7,6 +7,7 @@ from haystack import component, default_from_dict, default_to_dict
|
|
|
7
7
|
from haystack.dataclasses import Document
|
|
8
8
|
from haystack.document_stores.types import FilterPolicy
|
|
9
9
|
from haystack.document_stores.types.filter_policy import apply_filter_policy
|
|
10
|
+
|
|
10
11
|
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
11
12
|
from haystack_integrations.document_stores.pgvector.document_store import VALID_VECTOR_FUNCTIONS
|
|
12
13
|
|
|
@@ -126,7 +127,10 @@ class PgvectorEmbeddingRetriever:
|
|
|
126
127
|
"""
|
|
127
128
|
doc_store_params = data["init_parameters"]["document_store"]
|
|
128
129
|
data["init_parameters"]["document_store"] = PgvectorDocumentStore.from_dict(doc_store_params)
|
|
129
|
-
|
|
130
|
+
# Pipelines serialized with old versions of the component might not
|
|
131
|
+
# have the filter_policy field.
|
|
132
|
+
if filter_policy := data["init_parameters"].get("filter_policy"):
|
|
133
|
+
data["init_parameters"]["filter_policy"] = FilterPolicy.from_str(filter_policy)
|
|
130
134
|
return default_from_dict(cls, data)
|
|
131
135
|
|
|
132
136
|
@component.output_types(documents=List[Document])
|
|
@@ -7,6 +7,7 @@ from haystack import component, default_from_dict, default_to_dict
|
|
|
7
7
|
from haystack.dataclasses import Document
|
|
8
8
|
from haystack.document_stores.types import FilterPolicy
|
|
9
9
|
from haystack.document_stores.types.filter_policy import apply_filter_policy
|
|
10
|
+
|
|
10
11
|
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
11
12
|
|
|
12
13
|
|
|
@@ -100,7 +101,10 @@ class PgvectorKeywordRetriever:
|
|
|
100
101
|
"""
|
|
101
102
|
doc_store_params = data["init_parameters"]["document_store"]
|
|
102
103
|
data["init_parameters"]["document_store"] = PgvectorDocumentStore.from_dict(doc_store_params)
|
|
103
|
-
|
|
104
|
+
# Pipelines serialized with old versions of the component might not
|
|
105
|
+
# have the filter_policy field.
|
|
106
|
+
if filter_policy := data["init_parameters"].get("filter_policy"):
|
|
107
|
+
data["init_parameters"]["filter_policy"] = FilterPolicy.from_str(filter_policy)
|
|
104
108
|
return default_from_dict(cls, data)
|
|
105
109
|
|
|
106
110
|
@component.output_types(documents=List[Document])
|
|
@@ -9,7 +9,6 @@ from haystack.dataclasses.document import ByteStream, Document
|
|
|
9
9
|
from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumentError
|
|
10
10
|
from haystack.document_stores.types import DuplicatePolicy
|
|
11
11
|
from haystack.utils.auth import Secret, deserialize_secrets_inplace
|
|
12
|
-
from haystack.utils.filters import convert
|
|
13
12
|
from psycopg import Error, IntegrityError, connect
|
|
14
13
|
from psycopg.abc import Query
|
|
15
14
|
from psycopg.cursor import Cursor
|
|
@@ -389,7 +388,8 @@ class PgvectorDocumentStore:
|
|
|
389
388
|
msg = "Filters must be a dictionary"
|
|
390
389
|
raise TypeError(msg)
|
|
391
390
|
if "operator" not in filters and "conditions" not in filters:
|
|
392
|
-
|
|
391
|
+
msg = "Invalid filter syntax. See https://docs.haystack.deepset.ai/docs/metadata-filtering for details."
|
|
392
|
+
raise ValueError(msg)
|
|
393
393
|
|
|
394
394
|
sql_filter = SQL("SELECT * FROM {table_name}").format(table_name=Identifier(self.table_name))
|
|
395
395
|
|
|
@@ -11,9 +11,10 @@ from haystack.document_stores.errors import DuplicateDocumentError
|
|
|
11
11
|
from haystack.document_stores.types import DuplicatePolicy
|
|
12
12
|
from haystack.testing.document_store import CountDocumentsTest, DeleteDocumentsTest, WriteDocumentsTest
|
|
13
13
|
from haystack.utils import Secret
|
|
14
|
-
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
15
14
|
from pandas import DataFrame
|
|
16
15
|
|
|
16
|
+
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
17
|
+
|
|
17
18
|
|
|
18
19
|
@pytest.mark.integration
|
|
19
20
|
class TestDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocumentsTest):
|
|
@@ -6,9 +6,10 @@ from typing import List
|
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
8
|
from haystack.dataclasses.document import Document
|
|
9
|
-
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
10
9
|
from numpy.random import rand
|
|
11
10
|
|
|
11
|
+
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
12
|
+
|
|
12
13
|
|
|
13
14
|
@pytest.mark.integration
|
|
14
15
|
class TestEmbeddingRetrieval:
|
|
@@ -3,6 +3,10 @@ from typing import List
|
|
|
3
3
|
import pytest
|
|
4
4
|
from haystack.dataclasses.document import Document
|
|
5
5
|
from haystack.testing.document_store import FilterDocumentsTest
|
|
6
|
+
from pandas import DataFrame
|
|
7
|
+
from psycopg.sql import SQL
|
|
8
|
+
from psycopg.types.json import Jsonb
|
|
9
|
+
|
|
6
10
|
from haystack_integrations.document_stores.pgvector.filters import (
|
|
7
11
|
FilterError,
|
|
8
12
|
_convert_filters_to_where_clause_and_params,
|
|
@@ -10,9 +14,6 @@ from haystack_integrations.document_stores.pgvector.filters import (
|
|
|
10
14
|
_parse_logical_condition,
|
|
11
15
|
_treat_meta_field,
|
|
12
16
|
)
|
|
13
|
-
from pandas import DataFrame
|
|
14
|
-
from psycopg.sql import SQL
|
|
15
|
-
from psycopg.types.json import Jsonb
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@pytest.mark.integration
|
|
@@ -7,6 +7,7 @@ import pytest
|
|
|
7
7
|
from haystack.dataclasses import Document
|
|
8
8
|
from haystack.document_stores.types import FilterPolicy
|
|
9
9
|
from haystack.utils.auth import EnvVarSecret
|
|
10
|
+
|
|
10
11
|
from haystack_integrations.components.retrievers.pgvector import PgvectorEmbeddingRetriever, PgvectorKeywordRetriever
|
|
11
12
|
from haystack_integrations.document_stores.pgvector import PgvectorDocumentStore
|
|
12
13
|
|
|
@@ -241,6 +242,54 @@ class TestKeywordRetriever:
|
|
|
241
242
|
assert retriever.filters == {"field": "value"}
|
|
242
243
|
assert retriever.top_k == 5
|
|
243
244
|
|
|
245
|
+
@pytest.mark.usefixtures("patches_for_unit_tests")
|
|
246
|
+
def test_from_dict_without_filter_policy(self, monkeypatch):
|
|
247
|
+
monkeypatch.setenv("PG_CONN_STR", "some-connection-string")
|
|
248
|
+
t = "haystack_integrations.components.retrievers.pgvector.keyword_retriever.PgvectorKeywordRetriever"
|
|
249
|
+
data = {
|
|
250
|
+
"type": t,
|
|
251
|
+
"init_parameters": {
|
|
252
|
+
"document_store": {
|
|
253
|
+
"type": "haystack_integrations.document_stores.pgvector.document_store.PgvectorDocumentStore",
|
|
254
|
+
"init_parameters": {
|
|
255
|
+
"connection_string": {"env_vars": ["PG_CONN_STR"], "strict": True, "type": "env_var"},
|
|
256
|
+
"table_name": "haystack_test_to_dict",
|
|
257
|
+
"embedding_dimension": 768,
|
|
258
|
+
"vector_function": "cosine_similarity",
|
|
259
|
+
"recreate_table": True,
|
|
260
|
+
"search_strategy": "exact_nearest_neighbor",
|
|
261
|
+
"hnsw_recreate_index_if_exists": False,
|
|
262
|
+
"hnsw_index_creation_kwargs": {},
|
|
263
|
+
"hnsw_index_name": "haystack_hnsw_index",
|
|
264
|
+
"hnsw_ef_search": None,
|
|
265
|
+
"keyword_index_name": "haystack_keyword_index",
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
"filters": {"field": "value"},
|
|
269
|
+
"top_k": 5,
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
retriever = PgvectorKeywordRetriever.from_dict(data)
|
|
274
|
+
document_store = retriever.document_store
|
|
275
|
+
|
|
276
|
+
assert isinstance(document_store, PgvectorDocumentStore)
|
|
277
|
+
assert isinstance(document_store.connection_string, EnvVarSecret)
|
|
278
|
+
assert document_store.table_name == "haystack_test_to_dict"
|
|
279
|
+
assert document_store.embedding_dimension == 768
|
|
280
|
+
assert document_store.vector_function == "cosine_similarity"
|
|
281
|
+
assert document_store.recreate_table
|
|
282
|
+
assert document_store.search_strategy == "exact_nearest_neighbor"
|
|
283
|
+
assert not document_store.hnsw_recreate_index_if_exists
|
|
284
|
+
assert document_store.hnsw_index_creation_kwargs == {}
|
|
285
|
+
assert document_store.hnsw_index_name == "haystack_hnsw_index"
|
|
286
|
+
assert document_store.hnsw_ef_search is None
|
|
287
|
+
assert document_store.keyword_index_name == "haystack_keyword_index"
|
|
288
|
+
|
|
289
|
+
assert retriever.filters == {"field": "value"}
|
|
290
|
+
assert retriever.filter_policy == FilterPolicy.REPLACE # defaults to REPLACE
|
|
291
|
+
assert retriever.top_k == 5
|
|
292
|
+
|
|
244
293
|
def test_run(self):
|
|
245
294
|
mock_store = Mock(spec=PgvectorDocumentStore)
|
|
246
295
|
doc = Document(content="Test doc", embedding=[0.1, 0.2])
|
|
@@ -263,7 +312,7 @@ class TestKeywordRetriever:
|
|
|
263
312
|
)
|
|
264
313
|
res = retriever.run(query="test query", filters={"field2": "value2"})
|
|
265
314
|
|
|
266
|
-
mock_store.
|
|
315
|
+
mock_store.mock_calls[0].assert_called_once_with(
|
|
267
316
|
query="test query", filters={"field": "value", "field2": "value2"}, top_k=10
|
|
268
317
|
)
|
|
269
318
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|