chore: import upstream snapshot with attribution
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Docker image release / Build base image (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Has been cancelled
Tests / Check if changed (push) Has been cancelled
Tests / format (push) Has been cancelled
Tests / check-imports (push) Has been cancelled
Tests / Unit / macos-latest (push) Has been cancelled
Tests / Unit / ubuntu-latest (push) Has been cancelled
Tests / Unit / windows-latest (push) Has been cancelled
Tests / mypy (push) Has been cancelled
Tests / Integration / ubuntu-latest (push) Has been cancelled
Tests / Integration / macos-latest (push) Has been cancelled
Tests / Integration / windows-latest (push) Has been cancelled
Tests / notify-slack-on-failure (push) Has been cancelled
Tests / Mark tests as completed (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:22:28 +08:00
commit c56bef871b
9296 changed files with 1854228 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
from .errors import DocumentStoreError, DuplicateDocumentError, MissingDocumentError
__all__ = ["DocumentStoreError", "DuplicateDocumentError", "MissingDocumentError"]
+15
View File
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
class DocumentStoreError(Exception):
pass
class DuplicateDocumentError(DocumentStoreError):
pass
class MissingDocumentError(DocumentStoreError):
pass
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
import sys
from typing import TYPE_CHECKING
from lazy_imports import LazyImporter
_import_structure = {"document_store": ["InMemoryDocumentStore"]}
if TYPE_CHECKING:
from .document_store import InMemoryDocumentStore as InMemoryDocumentStore
else:
sys.modules[__name__] = LazyImporter(name=__name__, module_file=__file__, import_structure=_import_structure)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
from .filter_policy import FilterPolicy, apply_filter_policy
from .policy import DuplicatePolicy
from .protocol import DocumentStore
__all__ = ["apply_filter_policy", "DocumentStore", "DuplicatePolicy", "FilterPolicy"]
@@ -0,0 +1,319 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
from enum import Enum
from typing import Any, Literal
from haystack import logging
logger = logging.getLogger(__name__)
class FilterPolicy(Enum):
"""
Policy to determine how filters are applied in retrievers interacting with document stores.
"""
# Runtime filters replace init filters during retriever run invocation.
REPLACE = "replace"
# Runtime filters are merged with init filters, with runtime filters overwriting init values.
MERGE = "merge"
def __str__(self) -> str:
return self.value
@staticmethod
def from_str(filter_policy: str) -> "FilterPolicy":
"""
Convert a string to a FilterPolicy enum.
:param filter_policy: The string to convert.
:return: The corresponding FilterPolicy enum.
"""
enum_map = {e.value.lower(): e for e in FilterPolicy}
policy = enum_map.get(filter_policy.lower() if filter_policy else "")
if policy is None:
msg = f"Unknown FilterPolicy type '{filter_policy}'. Supported types are: {list(enum_map.keys())}"
raise ValueError(msg)
return policy
def is_comparison_filter(filter_item: dict[str, Any]) -> bool:
"""
Check if the given filter is a comparison filter.
:param filter_item: The filter to check.
:returns: True if the filter is a comparison filter, False otherwise.
"""
return all(key in filter_item for key in ["field", "operator", "value"])
def is_logical_filter(filter_item: dict[str, Any]) -> bool:
"""
Check if the given filter is a logical filter.
:param filter_item: The filter to check.
:returns: True if the filter is a logical filter, False otherwise.
"""
return "operator" in filter_item and "conditions" in filter_item
def combine_two_logical_filters(
init_logical_filter: dict[str, Any], runtime_logical_filter: dict[str, Any]
) -> dict[str, Any]:
"""
Combine two logical filters, they must have the same operator.
If `init_logical_filter["operator"]` and `runtime_logical_filter["operator"]` are the same, the conditions
of both filters are combined. Otherwise, the `init_logical_filter` is ignored and `
runtime_logical_filter` is returned.
__Example__:
```python
init_logical_filter = {
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.rating", "operator": ">=", "value": 3},
]
}
runtime_logical_filter = {
"operator": "AND",
"conditions": [
{"field": "meta.genre", "operator": "IN", "value": ["economy", "politics"]},
{"field": "meta.publisher", "operator": "==", "value": "nytimes"},
]
}
new_filters = combine_two_logical_filters(
init_logical_filter, runtime_logical_filter, "AND"
)
# Output:
{
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.rating", "operator": ">=", "value": 3},
{"field": "meta.genre", "operator": "IN", "value": ["economy", "politics"]},
{"field": "meta.publisher", "operator": "==", "value": "nytimes"},
]
}
```
"""
if init_logical_filter["operator"] == runtime_logical_filter["operator"]:
return {
"operator": str(init_logical_filter["operator"]),
"conditions": init_logical_filter["conditions"] + runtime_logical_filter["conditions"],
}
logger.warning(
"The provided logical operators, {parsed_operator} and {operator}, do not match so the parsed logical "
"filter, {init_logical_filter}, will be ignored and only the provided logical filter,{runtime_logical_filter}, "
"will be used. Update the logical operators to match to include the parsed filter.",
parsed_operator=init_logical_filter["operator"],
operator=runtime_logical_filter["operator"],
init_logical_filter=init_logical_filter,
runtime_logical_filter=runtime_logical_filter,
)
runtime_logical_filter["operator"] = str(runtime_logical_filter["operator"])
return runtime_logical_filter
def combine_init_comparison_and_runtime_logical_filters(
init_comparison_filter: dict[str, Any],
runtime_logical_filter: dict[str, Any],
logical_operator: Literal["AND", "OR", "NOT"],
) -> dict[str, Any]:
"""
Combine a runtime logical filter with the init comparison filter using the provided logical_operator.
We only add the init_comparison_filter if logical_operator matches the existing
runtime_logical_filter["operator"]. Otherwise, we return the runtime_logical_filter unchanged.
__Example__:
```python
runtime_logical_filter = {
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.rating", "operator": ">=", "value": 3},
]
}
init_comparison_filter = {"field": "meta.date", "operator": ">=", "value": "2015-01-01"}
new_filters = combine_init_comparison_and_runtime_logical_filters(
init_comparison_filter, runtime_logical_filter, "AND"
)
# Output:
{
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.rating", "operator": ">=", "value": 3},
{"field": "meta.date", "operator": ">=", "value": "2015-01-01"},
]
}
```
"""
if runtime_logical_filter["operator"] == logical_operator:
conditions = runtime_logical_filter["conditions"]
fields = {c.get("field") for c in conditions}
if init_comparison_filter["field"] not in fields:
conditions.append(init_comparison_filter)
else:
logger.warning(
"The init filter, {init_filter}, is ignored as the field is already present in the existing "
"filters, {filters}.",
init_filter=init_comparison_filter,
filters=runtime_logical_filter,
)
return {"operator": str(runtime_logical_filter["operator"]), "conditions": conditions}
logger.warning(
"The provided logical_operator, {logical_operator}, does not match the logical operator found in "
"the runtime filters, {filters_logical_operator}, so the init filter will be ignored.",
logical_operator=logical_operator,
filters_logical_operator=runtime_logical_filter["operator"],
)
runtime_logical_filter["operator"] = str(runtime_logical_filter["operator"])
return runtime_logical_filter
def combine_runtime_comparison_and_init_logical_filters(
runtime_comparison_filter: dict[str, Any],
init_logical_filter: dict[str, Any],
logical_operator: Literal["AND", "OR", "NOT"],
) -> dict[str, Any]:
"""
Combine an init logical filter with the runtime comparison filter using the provided logical_operator.
We only add the runtime_comparison_filter if logical_operator matches the existing
init_logical_filter["operator"]. Otherwise, we return the runtime_comparison_filter unchanged.
__Example__:
```python
init_logical_filter = {
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.rating", "operator": ">=", "value": 3},
]
}
runtime_comparison_filter = {"field": "meta.date", "operator": ">=", "value": "2015-01-01"}
new_filters = combine_runtime_comparison_and_init_logical_filters(
runtime_comparison_filter, init_logical_filter, "AND"
)
# Output:
{
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.rating", "operator": ">=", "value": 3},
{"field": "meta.date", "operator": ">=", "value": "2015-01-01"},
]
}
```
"""
if init_logical_filter["operator"] == logical_operator:
conditions = init_logical_filter["conditions"]
fields = {c.get("field") for c in conditions}
if runtime_comparison_filter["field"] in fields:
logger.warning(
"The runtime filter, {runtime_filter}, will overwrite the existing filter with the same "
"field in the init logical filter.",
runtime_filter=runtime_comparison_filter,
)
conditions = [c for c in conditions if c.get("field") != runtime_comparison_filter["field"]]
conditions.append(runtime_comparison_filter)
return {"operator": str(init_logical_filter["operator"]), "conditions": conditions}
logger.warning(
"The provided logical_operator, {logical_operator}, does not match the logical operator found in "
"the init logical filter, {filters_logical_operator}, so the init logical filter will be ignored.",
logical_operator=logical_operator,
filters_logical_operator=init_logical_filter["operator"],
)
return runtime_comparison_filter
def combine_two_comparison_filters(
init_comparison_filter: dict[str, Any],
runtime_comparison_filter: dict[str, Any],
logical_operator: Literal["AND", "OR", "NOT"],
) -> dict[str, Any]:
"""
Combine a comparison filter with the `init_comparison_filter` using the provided `logical_operator`.
If `runtime_comparison_filter` and `init_comparison_filter` target the same field, `init_comparison_filter`
is ignored and `runtime_comparison_filter` is returned unchanged.
__Example__:
```python
runtime_comparison_filter = {"field": "meta.type", "operator": "==", "value": "article"},
init_comparison_filter = {"field": "meta.date", "operator": ">=", "value": "2015-01-01"},
new_filters = combine_two_comparison_filters(
init_comparison_filter, runtime_comparison_filter, "AND"
)
# Output:
{
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.date", "operator": ">=", "value": "2015-01-01"},
]
}
```
"""
if runtime_comparison_filter["field"] == init_comparison_filter["field"]:
logger.warning(
"The parsed filter, {parsed_filter}, is ignored as the field is already present in the existing "
"filters, {filters}.",
parsed_filter=init_comparison_filter,
filters=runtime_comparison_filter,
)
return runtime_comparison_filter
return {"operator": str(logical_operator), "conditions": [init_comparison_filter, runtime_comparison_filter]}
def apply_filter_policy(
filter_policy: FilterPolicy,
init_filters: dict[str, Any] | None = None,
runtime_filters: dict[str, Any] | None = None,
default_logical_operator: Literal["AND", "OR", "NOT"] = "AND",
) -> dict[str, Any] | None:
"""
Apply the filter policy to the given initial and runtime filters to determine the final set of filters used.
The function combines or replaces the initial and runtime filters based on the specified filter policy.
:param filter_policy: The policy to apply when handling the filters. It can be one of the following:
- `FilterPolicy.REPLACE`: Runtime filters will replace the initial filters.
- `FilterPolicy.MERGE`: Runtime filters will be merged with the initial filters. If there are overlapping keys,
values from the runtime filters will overwrite those from the initial filters.
:param init_filters: The initial filters set during the initialization of the relevant retriever.
:param runtime_filters: The filters provided at runtime, usually during a query operation execution. These filters
can change for each query/retriever run invocation.
:param default_logical_operator: The default logical operator to use when merging filters (non-legacy filters only).
:returns: A dictionary containing the resulting filters based on the provided policy.
"""
if filter_policy == FilterPolicy.MERGE and runtime_filters and init_filters:
# now we merge filters
if is_comparison_filter(init_filters) and is_comparison_filter(runtime_filters):
return combine_two_comparison_filters(init_filters, runtime_filters, default_logical_operator)
if is_comparison_filter(init_filters) and is_logical_filter(runtime_filters):
return combine_init_comparison_and_runtime_logical_filters(
init_filters, runtime_filters, default_logical_operator
)
if is_logical_filter(init_filters) and is_comparison_filter(runtime_filters):
return combine_runtime_comparison_and_init_logical_filters(
runtime_filters, init_filters, default_logical_operator
)
if is_logical_filter(init_filters) and is_logical_filter(runtime_filters):
return combine_two_logical_filters(init_filters, runtime_filters)
return runtime_filters or init_filters
+12
View File
@@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
from enum import Enum
class DuplicatePolicy(Enum):
NONE = "none"
SKIP = "skip"
OVERWRITE = "overwrite"
FAIL = "fail"
+135
View File
@@ -0,0 +1,135 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
from typing import Any, Protocol
from haystack.dataclasses import Document
from haystack.document_stores.types.policy import DuplicatePolicy
class DocumentStore(Protocol):
"""
Stores Documents to be used by the components of a Pipeline.
Classes implementing this protocol often store the documents permanently and allow specialized components to
perform retrieval on them, either by embedding, by keyword, hybrid, and so on, depending on the backend used.
In order to retrieve documents, consider using a Retriever that supports the DocumentStore implementation that
you're using.
"""
def to_dict(self) -> dict[str, Any]:
"""
Serializes this store to a dictionary.
"""
...
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "DocumentStore":
"""
Deserializes the store from a dictionary.
"""
...
def count_documents(self) -> int:
"""
Returns the number of documents stored.
"""
...
def filter_documents(self, filters: dict[str, Any] | None = None) -> list[Document]:
"""
Returns the documents that match the filters provided.
Filters are defined as nested dictionaries that can be of two types:
- Comparison
- Logic
Comparison dictionaries must contain the keys:
- `field`
- `operator`
- `value`
Logic dictionaries must contain the keys:
- `operator`
- `conditions`
The `conditions` key must be a list of dictionaries, either of type Comparison or Logic.
The `operator` value in Comparison dictionaries must be one of:
- `==`
- `!=`
- `>`
- `>=`
- `<`
- `<=`
- `in`
- `not in`
The `operator` values in Logic dictionaries must be one of:
- `NOT`
- `OR`
- `AND`
A simple filter:
```python
filters = {"field": "meta.type", "operator": "==", "value": "article"}
```
A more complex filter:
```python
filters = {
"operator": "AND",
"conditions": [
{"field": "meta.type", "operator": "==", "value": "article"},
{"field": "meta.date", "operator": ">=", "value": 1420066800},
{"field": "meta.date", "operator": "<", "value": 1609455600},
{"field": "meta.rating", "operator": ">=", "value": 3},
{
"operator": "OR",
"conditions": [
{"field": "meta.genre", "operator": "in", "value": ["economy", "politics"]},
{"field": "meta.publisher", "operator": "==", "value": "nytimes"},
],
},
],
}
:param filters: the filters to apply to the document list.
:returns: a list of Documents that match the given filters.
"""
...
def write_documents(self, documents: list[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE) -> int:
"""
Writes Documents into the DocumentStore.
:param documents: a list of Document objects.
:param policy: the policy to apply when a Document with the same id already exists in the DocumentStore.
- `DuplicatePolicy.NONE`: Default policy, behaviour depends on the Document Store.
- `DuplicatePolicy.SKIP`: If a Document with the same id already exists, it is skipped and not written.
- `DuplicatePolicy.OVERWRITE`: If a Document with the same id already exists, it is overwritten.
- `DuplicatePolicy.FAIL`: If a Document with the same id already exists, an error is raised.
:raises DuplicateError: If `policy` is set to `DuplicatePolicy.FAIL` and a Document with the same id already
exists.
:returns: The number of Documents written.
If `DuplicatePolicy.OVERWRITE` is used, this number is always equal to the number of documents in input.
If `DuplicatePolicy.SKIP` is used, this number can be lower than the number of documents in the input list.
"""
...
def delete_documents(self, document_ids: list[str]) -> None:
"""
Deletes all documents with a matching document_ids from the DocumentStore.
Fails with `MissingDocumentError` if no document with this id is present in the DocumentStore.
:param document_ids: the object_ids to delete
"""
...