向量数据库的查询并不复杂,简单几条命令就可以搞定。而且,向量数据库的使用和传统数据库的使用逻辑相差不大,都是增删改查这一套。唯一有不同的就是向量计算和检索这块。
先简单来下Chroma在langchain中的检索:
from langchain.vectorstores import Chroma
import sentence_transformers
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
embedding = HuggingFaceEmbeddings(model_name='shibing624/text2vec-base-chinese')
persist_directory = './chromadb'
vectordb = Chroma(persist_directory=persist_directory, embedding_function=embedding)
query = "俄乌的关系如何?"
s = vectordb.similarity_search(query)
print(123, s)
/////
123 [Document(page_content='加意见和建议,以尽快启动加入欧盟的谈判。 26 日,1500 多名民众在比利时首都布鲁塞尔举\n\n行示威游行,呼吁采取外交手段解决俄乌冲突,通过谈判实现持久和平。有示威者打出“停止\n\n北约和美国在乌克兰的战争”标语。', metadata={'source': './russiaX.pdf'}), Document(page_content='综合路透社、雅虎新闻等网站 2023 年 3 月 9 日报道,乌克兰官员称,3 月 9 日早些时候,俄 罗斯发动空袭,袭击了乌克兰多个地区,包括黑海港口敖德萨和乌克兰第二大城市哈尔科夫, 导致多个地区断电。这是俄罗斯时隔 25 天以后再次发动大规模袭击,俄军上次大规模导弹袭 击还是 2 月 10 日。俄军当时使用了巡飞弹和巡航导弹。', metadata={'source': './russiaX.pdf'}), Document(page_content='乌克兰东部问....
可以看到,检索出了四条数据,在意料之中。但是,如果你检索一个完全不相关的问题,它也会返回四条数据! 这就有点让人难接受了,那么,要如何查询出最相关的数据呢?
similarity_search_with_score 函数
Chroma中除了similarity_search
,还有另一个更适宜的函数similarity_search_with_score
。它不仅会返回数据,还会同时将相关度数值(score)一起返回。对数据进行判断,再决定是否要采用此数据。
# 它不仅允许你返回文档,还允许你返回查询与文档的距离分值。
# 这个分值是余弦值, 同时越低越是相关。
# 源码如下,写得还是比较清楚,返回的数据是文档和数值
def similarity_search_with_score(
self,
query: str,
k: int = DEFAULT_K,
filter: Optional[Dict[str, str]] = None,
**kwargs: Any,
) -> List[Tuple[Document, float]]:
"""Run similarity search with Chroma with distance.
Args:
query (str): Query text to search for.
k (int): Number of results to return. Defaults to 4.
filter (Optional[Dict[str, str]]): Filter by metadata. Defaults to None.
Returns:
List[Tuple[Document, float]]: List of documents most similar to
the query text and cosine distance in float for each.
Lower score represents more similarity.
"""
相关度数值(score)还是挺迷的,到底多少算是相关,多少算是不相关呢?这里,我做了一些测试。 用的都是中文,向量计算embedding
就采用了shibing624/text2vec-base-chinese
这个库,计算出的数据经过一番比较,得到:低于256的算是相关度高,高于300的就基本不相关了!
下面是一段示例的文本,可以得到一个更直接的数据。
孙少平是什么时候开始上学的?
[(Document(page_content='时间长了一些,班上同学之间也开始变得熟悉起来。他和乡里来的一些较贫困的学生初步建立起了某种友谊关系。由于他读书多,许多人很爱听他讲书中的故事。这一点使孙少平非常高兴,觉得自己并不是什么都低人一等。加上气候变暖,校园里已经桃红柳绿,他的心情开朗了许多。而且他的单衣薄裳现在穿起来倒也正合适,不冷不热。除过肚子照样填不饱外,其它方面应该说相当令人满意了。\n\n这天下午劳动,全班学生在学校后面的一条拐沟里挖他们班种的地。不到一个小时,孙少平就感到饿得头晕眼花。他有气无力地抡着镰头,尽量使自己不落在别人的后面。\n\n好不容易熬到快要收工的时候,他们村的润生突然来到他眼前,说:“少平,我姐中午来找我,说让我把你带上,下午到我二爸家去一下。她说有个事要给你说。我姐还说让你下午别在学校灶上吃,到我二爸家去吃饭……。”润生说完这话,就又回到他挖地的地方去了。\n\n孙少平一下子被这意外的邀请弄得不知所措。', metadata={'source': './uploads/pinfan.txt'}), 247.78954649945229), (Document(page_content='那天班上学习《人民日报》社论《领导干部带头学好》的文章,班主任主持,班长顾养民念报纸。孙少平一句也没听,低着头悄悄在桌子下面看小说。他根本没有发现跛女子给班主任老师示意他的不规行为。直等到老师走到他面前,把书从他手里一把夺过之后,他才猛地惊呆了。全班顿时哄堂大笑。顾养民不念报了,他看来似乎是一副局外人的样子,但孙少平觉得班长分明抱着一种幸灾乐祸的态度,看老师怎样处置他呀。\n\n班主任把没收的书放在讲桌上,先没说什么,让顾养民接着往下念。 学习完了以后,老师把他叫到宿舍,意外地把书又还给了他,并且说:“《红岩》是一本好书,但以后你不要在课堂上看了。去吧……”', metadata={'source': './uploads/pinfan.txt'}), 283.42653059964454), (Document(page_content='每天,只要学校没什么事,孙少平就一个人出去在城里的各种地方转:大街小巷,城里城外,角角落落,反正没去过的地方都去。除过几个令人敬畏的机关――如县革委会、县武装部和县公安局外,他差不多在许多机关的院子里都转过了――大多是假装上厕所而哄过门房老头进去的。由于人生地不熟,他也不感到这身破衣服在公众场所中的寒酸,自由自在地在这个城市的四面八方逛荡。他在这其间获得了无数新奇的印象,甚至觉得弥漫在城市上空的炭烟味闻起来都是别具一格的。当然,许许多多新的所见所识他都还不能全部理解,但所有的一切无疑都在他的精神上产生了影响。透过城市生活的镜面,他似乎更清楚地看见了他已经生活过十几年的村庄――在那个位所熟悉的古老的世界里,原来许多有意义的东西,现在看起来似乎有点平淡无奇了。而那里许多本来重要的事物过去他却并没有留心,现在倒突然如此鲜活地来到了他的心间。', metadata={'source': './uploads/pinfan.txt'}), 289.530431265032), (Document(page_content='“和晓霞不一个班,和润生是一个班。”润叶回答他。“咱村里还有谁家的娃娃来上高中了?”田主任又问少平。少平拘束地抠着手指头,说:“还有金波。”\n\n“金波?他的娃娃……”\n\n少平头“轰”地响了一声,知道他回答问题不准确。润叶嘿嘿笑了,赶忙对二爸说:“金波是金俊海的小子。”田主任也笑了,说:“噢噢,俊海在地区运输公司开车……天这么黑了,到家里吃饭去嘛!”他招呼少平说。润叶说:“已经吃过了。我去送送他!”\n\n“那好。常来啊……”田主任竟然伸出了手要和少平握手。\n\n少平慌得赶紧把手伸了出去。田主任握了握他的手,笑着点点头,就背抄起胳膊转身回家去了。\n\n少平在衣服襟子上把右手冒出的汗水揩了揩,就跟润叶来到通往中学的石坡路上。\n\n走了一段路以后,润叶突然问他:“你这个星期六回不回家去?”\n\n“回。”他回答说。', metadata={'source': './uploads/pinfan.txt'}), 290.06170660039527)]
所以,在做向量数据库查询时,最好使用similarity_search_with_score
这个函数,同时对相关度数值做个判断,比较相关的数据可以采用,不相关的不采用,这样才会得到比较满意的结果。