llama_index [Bug]: Weaviate MetadataFilters break on "numeric" strings

5lwkijsr  于 5个月前  发布在  其他
关注(0)|答案(8)|浏览(42)

错误描述

在将llama索引从0.8.50更新到0.9.35后,我的向量查询出现了问题。使用包含数值的字符串作为元数据过滤器的valueText字段时,会抛出错误,抱怨valueNumber与valueText不匹配。

版本

0.9.35

重现步骤

你只需要在元数据过滤器中有一个数值字符串作为valueText字段,就会出现这个错误。
这似乎是llama_index/llama_index/vector_stores/weaviate.py文件中的第78行代码引起的,但不确定为什么那一行最初会被添加进来。
851399a

相关日志/回溯

import weaviate
from llama_index.schema import TextNode
from llama_index.vector_stores.weaviate import WeaviateVectorStore
from llama_index.vector_stores.types import MetadataFilters, MetadataFilter, VectorStoreQuery

client = weaviate.Client(url="http://localhost:8080")
vector_store = WeaviateVectorStore(weaviate_client=client, index_name="TestIndex", text_key="text")

vector_store.add(
    [
        TextNode(
            text="test 1",
            metadata={"article_id": "aaff"},
            embedding=[0, 0, 1],
        ),
        TextNode(
            text="test 2",
            metadata={"article_id": "1234"},
            embedding=[0, 1, 0],
        ),
        TextNode(
            text="test 3",
            metadata={"article_id": "3ff3"},
            embedding=[1, 0, 0],
        )
    ]
)

# -- working query
query = VectorStoreQuery(
    query_embedding=[0, 0, 0],
    similarity_top_k=2,
    filters=MetadataFilters(
        filters=[
            MetadataFilter(key="article_id", value="3ff3") # NOTE: works fine because is not a number
        ]
    )
)
results = vector_store.query(query)
print(results)

# -- below query breaks
query = VectorStoreQuery(
    query_embedding=[0, 0, 0],
    similarity_top_k=2,
    filters=MetadataFilters(
        filters=[
            MetadataFilter(key="article_id", value="1234") # NOTE: breaks because it's a number but the metadata field is a text field
        ]
    )
)
results = vector_store.query(query)
print(results)
up9lanfz

up9lanfz1#

你好,@KristianMischke!很高兴再次见到你。希望你的一天过得很好。让我们来解决你面临的这个问题。
感谢你提供了关于你所面临的问题的详细描述。问题似乎与LlamaIndex中的WeaviateVectorStore类如何处理带有数字字符串的元数据过滤器有关。
从你提供的回溯信息来看,错误消息表明WeaviateVectorStore试图将valueNumber字段用于文本类型,从而导致了问题。这很可能是因为WeaviateVectorStore没有正确识别元数据过滤器值的类型,并将其视为数字,因为它包含数字字符,尽管实际上它是一个字符串。
你在weaviate.py文件中指出的那一行代码是_to_weaviate_filter函数的一部分,该函数用于将标准过滤器转换为Weaviate特定过滤器。然后,这个函数被用作WeaviateVectorStore类的query方法中应用这些过滤器到查询的方法。
至于为什么这一行被添加,没有更多的上下文很难说肯定,但有可能它是有意处理元数据过滤器值实际上是数字而不是包含数字字符的字符串的情况。
不幸的是,根据提供的上下文,我无法在LlamaIndex版本0.8.50和0.9.35之间找到任何关于MetadataFilters处理方式的变化,或者在最新版本0.9.36中的变化。
要解决这个问题,一个可能的解决方案是更新_to_weaviate_filter函数,以便正确识别元数据过滤器值的类型,并根据其类型使用适当的字段(对于数字使用valueNumber,对于字符串使用valueText)。
希望这有所帮助!如果你有任何其他问题或需要进一步澄清,请随时提问。
Source Code

来源

此回复旨在节省您的时间并提供帮助。它不是精确的解决方案,而是您自己研究的一个起点。
请帮助我变得更有用!如果这有帮助请点赞👍,如果无关请点踩👎。
如果你想继续对话,请以@dosu-bot开头回复。

xkrw2x1b

xkrw2x1b2#

感谢@KristianMischke的提醒。看起来你关于这个bug出自代码何处的判断是正确的。我在思考如何最好地解决这个问题。我们可能需要为MetadataFilters暴露另一个参数,该参数规定如何处理可以转换为数字的字符串。

MetadataFilter(key="article_id", value="1234", value_type="str")

其中value_type是一个枚举类型。
@logan-markewich你怎么看?

s71maibg

s71maibg3#

我想知道是否有办法使用Weaviate来检查字段的类型,并在创建Weaviate过滤器时强制转换为正确的类型?

l7wslrjt

l7wslrjt4#

好的点子。我同意——这应该是我们在这里首先考虑的。

plicqrtu

plicqrtu5#

分配了P1优先级@logan-markewich。如果您觉得有必要,请更改此设置。

txu3uszq

txu3uszq6#

是的,Weaviate模式属性具有数据类型:https://weaviate.io/developers/weaviate/config-refs/datatypes,可用于转换。

dfuffjeb

dfuffjeb7#

我遇到了相同的问题,与llamaindex-raptor pack有关。

vector_store = WeaviateVectorStore(weaviate_client=vdb_client,
 index_name="RaptorIndex",
 text_key="text")
retriever = RaptorRetriever(
 [],
 embed_model=embed_model, # 用于嵌入聚类
 llm=llm_model, # 用于生成摘要
 vector_store=vector_store, # 用于存储
 similarity_top_k=2, # 每层的前k个,或折叠后的总体前k个
 mode="tree_traversal", # 设置默认模式
 )
query_engine = RetrieverQueryEngine.from_args(
 retriever, llm=llm_model
 )
response = query_engine.query("What baselines was RAPTOR compared against?")

错误:-

{'data': {'Get': {'RaptorIndex': None}}, 'errors': [{'locations': [{'column': 6, 'line': 1}], 'message': 'invalid \'where\' filter: data type filter cannot use "valueInt" on type "number", use "valueNumber" instead', 'path': ['Get', 'RaptorIndex']}]}
上述代码有任何问题吗?
使用的包:
llama-index-vector-stores-weaviate = "^0.1.4" llama-index-packs-raptor = "^0.1.3" llama-index-llms-ollama = "^0.1.2" llama-index-embeddings-ollama = "^0.1.2" umap-learn = "^0.5.6"

yks3o0rb

yks3o0rb8#

我已经解决了所识别的问题。在遇到类似问题时,我进行了一些小的修改。由于这只是一个临时解决方案,还需要更多的工作。
已更新以下文件以反映更改:

  • llama_index/core/vector_stores/init.py
from llama_index.core.vector_stores.simple import SimpleVectorStore
from llama_index.core.vector_stores.types import (
    ExactMatchFilter,
    FilterCondition,
    FilterOperator,
    MetadataFilter,
    MetadataFilters,
    MetadataInfo,
    VectorStoreQuery,
    VectorStoreQueryResult,
    VectorStoreInfo,
    ValueDataType
)

__all__ = [
    "VectorStoreQuery",
    "VectorStoreQueryResult",
    "MetadataFilters",
    "MetadataFilter",
    "MetadataInfo",
    "ExactMatchFilter",
    "FilterCondition",
    "FilterOperator",
    "SimpleVectorStore",
    "VectorStoreInfo",
    "ValueDataType"
]
  • llama_index/vector_stores/weaviate/base.py
def _to_weaviate_filter(standard_filters: MetadataFilters) -> Dict[str, Any]:
    filters_list = []
    condition = standard_filters.condition or "and"
    condition = _transform_weaviate_filter_condition(condition)

    if standard_filters.filters:
        for filter in standard_filters.filters:
            print(filter)
            value_type = "valueText"
            if filter.value_type.casefold() == "string":
                value_type = "valueText"
            elif isinstance(filter.value, float):
                value_type = "valueNumber"
            elif isinstance(filter.value, int):
                value_type = "valueInt"
            elif isinstance(filter.value, str) and filter.value.isnumeric():
                filter.value = float(filter.value)
                value_type = "valueNumber"
            filters_list.append(
                {
                    "path": filter.key,
                    "operator": _transform_weaviate_filter_operator(filter.operator),
                    value_type: filter.value,
                }
            )
    else:
        return {}

    if len(filters_list) == 1:
        # If there is only one filter, return it directly
        return filters_list[0]

    return {"operands": filters_list, "operator": condition}
  • llama_index/core/vector_stores/types.py
class ValueDataType(str, Enum):
    """Value Data Type Class."""
    STRING = "STRING"  # Text data
    INTEGER = "INT"     # Integer data
    FLOAT = "FLOAT"    # Floating-point data
    BOOLEAN = "BOOLEAN"  # True or False data
    DATETIME = "DATETIME"  # Date and time data
    LOCATION = "LOCATION"  # Geographical location data
    # Add more data types as needed

    def __str__(self):
        """Returns the string representation of the data type."""
        return self.value

class MetadataFilter(BaseModel):
    """Comprehensive metadata filter for vector stores to support more operators.

    Value uses Strict* types, as int, float and str are compatible types and were all
    converted to string before.

    See: https://docs.pydantic.dev/latest/usage/types/#strict-types
    """

    key: str
    value: Union[
        StrictInt,
        StrictFloat,
        StrictStr,
        List[Union[StrictInt, StrictFloat, StrictStr]],
    ]
    value_type: ValueDataType = ValueDataType.STRING
    operator: FilterOperator = FilterOperator.EQ

    @classmethod
    def from_dict(
        cls,
        filter_dict: Dict,
    ) -> "MetadataFilter":
        """Create MetadataFilter from dictionary.

        Args:
            filter_dict: Dict with key, value and operator.

        """
        return MetadataFilter.parse_obj(filter_dict)

用法:

MetadataFilters(
                filters=[
                    MetadataFilter(
                        key="field_name",
                        value=field_value,
                        value_type=ValueDataType.STRING
                    )
                    for field_value in fields
                ],
                condition=FilterCondition.AND
            )

希望这有所帮助!任何建议或反馈都是受欢迎的

相关问题