如何使用 Sentence Transformers 将元数据用于文档检索?

How to use metadata for document retrieval using Sentence Transformers?

我正在尝试使用 Sentence Transformers 和 Haystack 进行文档检索,重点是在文档文本之外的其他元数据上搜索文档。

我正在使用学术出版物标题的数据集,并且附加了一个虚假的出版年份(我想将其用作搜索词)。通过四处阅读,我合并了各列,并在标题和出版年份之间添加了一个分隔符,并包含了列标题,因为我认为这可能会增加上下文。输入示例如下:

title Sparsity-certifying Graph Decompositions [SEP] published year 1980

我这里有一个文档存储和检索方法,基于this:

document_store_faiss = FAISSDocumentStore(faiss_index_factory_str="Flat",
                                          return_embedding=True,
                                          similarity='cosine')

retriever_faiss = EmbeddingRetriever(document_store_faiss,
                                     embedding_model='all-mpnet-base-v2',
                                     model_format='sentence_transformers')

document_store_faiss.write_documents(df.rename(columns={'combined':'content'}).to_dict(orient='records'))
document_store_faiss.update_embeddings(retriever=retriever_faiss)

def get_results(query, retriever, n_docs = 25):
  return [(item.content) for item in retriever.retrieve(q, top_k = n_docs)]

q = 'published year 1999'
print('Results: ')
res = get_results(q, retriever_faiss) 
for r in res:
  print(r) 

我检查是否有任何输入实际上具有与搜索词匹配的出版年份,但是当我查看我的搜索结果时,我得到的条目似乎是随机出版年份。我希望至少所有的结果都是相同的出版年份,因为我希望做更复杂的查询,比如 "published year before 1980".

如果有人能告诉我我做错了什么,或者我是否误解了这个过程/预期结果,我们将不胜感激。

听起来您需要元数据过滤而不是将年份放在查询本身中。 FaissDocumentStore 不支持过滤,我建议切换到几天前 Haystack 在 v1.3 版本中引入的 PineconeDocumentStore。支持当前文档存储集中最强的过滤功能

您需要确保安装了最新版本的 Haystack,它还需要一个额外的 pinecone-client 库:

pip install -U farm-haystack pinecone-client

有一个 guide here 可能会有帮助,它会是这样的:

document_store = PineconeDocumentStore(
    api_key="<API_KEY>", # from https://app.pinecone.io
    environment="us-west1-gcp"
)
retriever = EmbeddingRetriever(
    document_store,
    embedding_model='all-mpnet-base-v2',
    model_format='sentence_transformers'
)

在编写文档之前,您需要转换数据以在 content 中包含您的文本(正如您在上面所做的那样,但不需要 pre-append 年份),然后包含年份作为 meta 字典中的一个字段。因此,您将创建一个字典列表,如下所示:

dicts = [
    {'content': 'your text here', 'meta': {'year': 1999}},
    {'content': 'another record text', 'meta': {'year': 1971}},
    ...
]

我不知道你的 df 的确切格式,但假设它是这样的:

text year
"your text here" 1999
"another record here" 1971

我们可以编写以下代码来重新格式化它:

df = df.rename(columns={'text': 'content'})  # you did this already

# create a new 'meta' column that contains {'year': <year>} data
df['meta'] = df['year'].apply(lambda x: {'year': x})

# we don't need the year column anymore so we drop it
df = df.drop(['year'], axis=1)

# now convert into the list of dictionaries format as you did before
dicts = df.to_dict(orient='records')

此数据将替换您编写的 df 词典,因此我们将继续这样做:

document_store.write_documents(dicts)
document_store.update_embeddings(retriever=retriever)

现在您可以使用过滤器进行查询,例如要搜索发布年份为 1999 的文档,我们使用条件 "$eq"(等于):

docs = retriever.retrieve(
    "some query here",
    top_k=25,
    filters={
        {"year": {"$eq": 1999}}
    }
)

对于1980年之前发表的我们可以使用"$lt"(小于):

docs = retriever.retrieve(
    "some query here",
    top_k=25,
    filters={
        {"year": {"$lt": 1980}}
    }
)