学有所记——初探向量数据库Weaviate
目标:
了解向量数据库的连接、建库、插入数据、查询数据等基本用法以及关于语义相似度的一些基本概念。
背景:
前段时间尝试在自己的电脑上搭建Ollama+Dify平台,体验并探索大模型的强大功能。在使用过程中,尤其是在搭建RAG知识库过程中,遇到了检索不理想,以及Dify自带的知识库构建,存在一些功能性限制的问题(例如每次只能获取特定数量记录),虽然可以通过调整环境参数进行修改。另外,在批量导入知识的过程中,也存在分块不够理想的问题,于是萌发了跳过Dify,直接连接Weaviate数据库进行操作的想法,于是进行了一些探索。
解决过程:
基本环境为 Win11 home + PyCharm 2024.3.3 社区版 + Python3.11(venv虚拟环境)
用到的库包括 weaviate-client,sentence_transformers 等,以及模型 baai\bge-reranker-v2-m3
一、安装和下载
用Pip 安装 weaviate-client sentence_transformers
pip install weaviate-client sentence_transformers
去 https://hf-mirror.com/ 下载模型库和测试数据集 BAAI/bge-reranker-v2-m3 · HF Mirrorhttps://hf-mirror.com/BAAI/bge-reranker-v2-m3
FreedomIntelligence/medical-o1-reasoning-SFT · Datasets at Hugging Facehttps://hf-mirror.com/datasets/FreedomIntelligence/medical-o1-reasoning-SFT/viewer/zh
二、连接数据库服务
import json
import weaviate
from sentence_transformers import SentenceTransformer
from weaviate.auth import Auth
from weaviate.classes.query import MetadataQueryweaviate_api_key = "WVF5YsdfkYwhfasdfsX3dsfsddN8pkih" #根据自己的的docker进行设置
# 连接 Weaviate
client = weaviate.connect_to_local(host="127.0.0.1",port=8080,grpc_port=50051,auth_credentials=Auth.api_key(weaviate_api_key),
)meta = client.get_meta()
print("已加载模块:", meta["modules"])
print("客户端是否已连接数据库?",client.is_ready())
三、创建数据库
# 创建一个名为my_collect的集合collection_name = "My_collect_2"client.collections.delete(collection_name) #每次执行,删除先前的数据库if collection_name not in client.collections.list_all(): # 判断是否存在,如果已存在就跳过class_obj = {"class": collection_name,"vectorizer": None,"vectorIndexConfig": {"distance": "cosine","efConstruction": 256, # 重点调整此参数"maxConnections": 64, # 每层最大连接数(影响图密度)"ef": 128 # 查询时动态调整},"properties": [{"name": "content", "dataType": ["text"]}]}client.collections.create_from_dict(class_obj)
四、初始化向量化模型(用于text2vec)
model = SentenceTransformer(r"D:\MyDevelop\MOD\huggingface\baai\bge-reranker-v2-m3")
五、准备数据
从网上的医疗问答数据中,提取了若干条做测试。另存为 testdata.jsonFreedomIntelligence/medical-o1-reasoning-SFT · Datasets at Hugging Facehttps://hf-mirror.com/datasets/FreedomIntelligence/medical-o1-reasoning-SFT/viewer/zh数据内容举例如下:
[{"Question": "一位5岁的男孩入院,症状包括发热、头痛和嗜睡4天。血常规显示白细胞总数为15×10^9/L,中性粒细胞占85%,淋巴细胞占15%。脑脊液检查结果为细胞总数100×10^6/L,中性粒细胞占70%,蛋白质含量为0.6g/L,糖浓度为3mmol/L,氯化物浓度为198mmol/L。这名患者最可能患有什么病?","Complex_CoT": "好,现在我们有一个5岁的小男孩,他有发热、头痛和嗜睡的症状,这些症状已经持续了4天。听起来像是感染引起的,尤其是可能与中枢神经系统有关。让我们看看他的血常规结果。\n\n血常规显示白细胞数增高到15×10^9/L,这里中性粒细胞多达85%,而淋巴细胞才占15%。这个比例通常会让我想细菌感染,因为细菌感染通常会让中性粒细胞增加。\n\n接下来是脑脊液检查。看看,这里有些有趣的发现。脑脊液细胞数是100×10^6/L,其中70%是中性粒细胞,蛋白质含量是0.6g/L,糖含量为3mmol/L,还有氯化物浓度高达198mmol/L。这些信息在一起指向什么呢?\n\n如果是化脓性脑膜炎,脑脊液中糖一般会降低,但是现在这个糖却是正常的。这有点出乎意料。但是中性粒细胞比例确实很高,正常情况下确实像是一个细菌感染,是不是早期没表现出典型症状?\n\n再想想,为什么氯化物浓度会这么高呢?这也不太典型啊,得看看是不是有什么特殊病原体或者其他病因。\n\n哦,对了,也不能忘记考虑病毒性脑膜炎,在某些情况下,它的脑脊液糖值是正常的,而且蛋白质轻微升高。特别是在一些病毒性脑膜炎,刚开始的时候,中性粒细胞可能会高过淋巴细胞,虽然不太常见。这是不是能解释确定更多呢?\n\n想到流行性乙型脑炎(乙脑),会有急性发热、头痛和嗜睡症状,而且,在早期的脑脊液分析中,也可能看到中性粒细胞比例偏高,糖浓度正常。是不是这就是我们要找的呢?\n\n仔细想想,现在的所有症状特征和检查结果都很适合描述乙脑的情况。这样的话,考虑乙型脑炎就更加符合这个小男孩的临床表现。这个思路让我的解释更连贯,更有逻辑。\n\n所以,总结一下,最可能的原因是患者感染了流行性乙型脑炎(乙脑),这比较好地解释了发热、头痛以及其他临床表现,还有不太典型的脑脊液检查特征。看来这一结论是更加合理且符合他现在的症状的。","Response": "根据你的描述和提供的检查结果,这名5岁男孩最可能患的是流行性乙型脑炎(乙脑)。他所表现的症状如发热、头痛和嗜睡,以及血液和脑脊液的检查结果都较符合乙脑的特点。乙脑患者的脑脊液常在早期表现为中性粒细胞比例增高,但糖浓度往往正常,这与报告中的结果一致。因此,流行性乙型脑炎是一个合理的诊断方向。建议对该患者进行进一步的病毒学检查以确认诊断,并尽早开始相关的治疗。"},{"Question": "一名三十五岁男性患者因发热及口腔黏膜糜烂前来就诊,伴有不洁性交史,查体显示全身淋巴结肿大,咽部黏膜糜烂,唇黏膜多发灰白色斑块,并且梅毒血清试验强阳性,请问该患者最可能的临床诊断是什么阶段的梅毒?","Complex_CoT": "这名患者今年35岁,是个男性,他来医院是因为发烧,还有口腔黏膜的糜烂,哎,还有重要的一点,他有过不洁的性交史。现在先根据这些线索来考虑可能的疾病。身体检查后发现他的全身淋巴结肿大,喉咙的黏膜也出现了糜烂现象,而且嘴唇上有多发性的灰白色斑块。这看起来情况并不简单,幸好梅毒的血清试验显示阳性,提供了一个关键的证据。\n\n那么我们就得仔细分析一下梅毒的不同阶段了。一般来说,一期梅毒通常会出现硬下疳和局部淋巴结肿大,但这种阶段的症状好像不太会涉及全身症状,也不常见口腔黏膜糜烂,感觉稍微不符。\n\n接着看二期梅毒,哦,是的,二期梅毒确实会有全身症状,经常伴随着全身淋巴结肿大,口腔和咽喉部的病变。更重要的是,还会有皮肤和黏膜上的斑丘疹或斑块,这和患者目前的描述相符得多。\n\n还有一个阶段就是三期梅毒,不过又想想,三期梅毒一般倾向于多系统病变,如皮肤、粘膜和骨骼等方面的损害。可这阶段的梅毒病情发展通常较长,不太会突然出现发热这些急性症状。所以我们应该可以暂时排除这个可能。\n\n综合来看,这位患者的情况最符合继发性梅毒的表现,特别是全身淋巴结肿大和口腔及唇部的病变,嗯,是二期梅毒没错。","Response": "根据您的描述,这位患者的临床表现最符合二期梅毒的特征。二期梅毒常见的症状包括全身性淋巴结肿大、皮肤和黏膜的病变,以及如口腔和咽喉部位的糜烂病变,尤其是唇黏膜多发灰白色斑块。此外,二期梅毒也可以出现发热等全身症状。结合患者的梅毒血清试验呈强阳性,可以较为肯定地诊断为二期梅毒。"},{"Question": "根据某地1970年的数据,该地总人口为20万,全死因死亡2000例。请计算该地1970年的粗死亡率(以每1000人为单位)。","Complex_CoT": "哦,我需要计算1970年某地的粗死亡率,那么首先要搞清楚这个概念。粗死亡率就是每年每1000人中有多少人死亡。这听起来有点简单,只需要知道总死亡人数和总人口就行。\n\n让我先看看给定的数据。嗯,该地的人口是20万,而死亡人数是2000。这些数字我都知道了,那么接下来就代入公式来算粗死亡率。\n\n公式是:粗死亡率等于总死亡人数除以总人口,再乘以1000。好的,我慢慢来,先算2000除以20万,这结果是0.01。\n\n这样看来,这个0.01就表示对于总人口来说,有0.01比例的人去世了。但因为粗死亡率是每千人计算的,所以我还得乘以1000。\n\n乘完之后,我得到0.01乘以1000,结果是10。哦,原来如此,这就是说在1970年,那里每1000人中就有10人去世。\n\n嗯,让我再确认一遍。2000死亡,20万人,这确实是0.01哦。然后乘以1000也确实是10。没错,我的计算和逻辑都没问题,粗死亡率果然是10每千人。","Response": "根据1970年的数据,该地总人口为20万,死亡人数为2000人。粗死亡率的计算公式是用总死亡人数除以总人口,然后乘以1000。\n\n因此,粗死亡率 = (2000 / 200000) × 1000 = 10。\n\n所以,该地1970年的粗死亡率为每千人10例。"},{"Question": "一名患者血压为110/80mmHg,心肺查体未见异常,腹部触诊呈揉面感,可见肠型及蠕动波,肠鸣音亢进。在这种情况下,为明确诊断该患者首选进行什么检查?","Complex_CoT": "好,我们来看看这个患者的情况。他的血压是110/80mmHg,这个相对来说是正常的水平。而且心肺检查也没有发现异常,这说明心肺系统的问题可以暂时排除掉。不过,当我们检查他的腹部时,发现触诊的时候有种像揉面的感觉,通常这种感觉可能意味着腹部肌肉相对松弛,也可能是肠道方面的异常反应。\n\n接下来的观察更加有趣,腹部可以看到肠型和蠕动波。哦,而且肠鸣音亢进,这些迹象似乎都在指向肠道活动增加,尤其可能是因为某种梗阻或者通路不畅导致的。\n\n那么,根据目前所有的表现,我会考虑这个患者可能存在肠梗阻的问题。这会导致肠道的功能异常,可能形成某种程度的梗阻,影响正常的消化和运动。\n\n接着是选择哪种检查来进一步确认我的猜测。如果真的是肠梗阻问题,我觉得最直接有效的方法应该是做一个腹部X光检查。为什么呢?因为通过X光可以看到肠道的积气情况和是否有液平面,这些都是判断肠梗阻的重要线索,而且这种检查相对快速又安全。\n\n所以,我决定,先安排这个患者做个腹部X光来确认我的初步判断。这样我们就可以明确有没有肠梗阻,然后再制定下一步的治疗方案。","Response": "在这种情况下,为了明确诊断该患者是否存在肠梗阻,首选的检查是腹部X光。这项检查可以帮助观察肠道内是否存在积气或液平面,从而判断是否有肠梗阻的存在。这是一个快速且相对安全的方法,有助于进一步明确诊断。"},{"Question": "一名57岁男性患者,患有冠心病,出现急性剧烈胸痛,血CPK明显升高,颈静脉充盈,肝大,血压下降至10.6/5.3kPa(80/40mmHg),应诊断为哪种病症?","Complex_CoT": "患者是一位57岁的男性,已经确定患有冠心病。而现在,他正经历着一种急性剧烈的胸痛。嗯,这种情况让我第一时间想到的是急性心肌梗死,毕竟这是冠心病患者常见的麻烦。而且,血液里面的CPK值也显著升高,这通常是因为心肌受损了。\n\n想想看,患者还有颈静脉充盈和肝脏增大,这些症状让我怀疑,是否存在右心衰竭呢?但再看他的血压,竟然降到了10.6/5.3kPa(80/40mmHg),这么低的血压确实不容忽视,意味着有可能是更严重的心脏问题,或者是心脏压塞这种迅速恶化的情况。\n\n不过,急性心肌梗死有时候也可能引起心脏压塞,这会导致心包里面聚集了过多的液体,进而出现颈静脉充盈、肝大和血压下降。心源性休克也可能是候选者之一,它也伴随着急剧的低血压。\n\n此刻,我开始把注意力更多地放在这些症状的组合上,右心室心肌梗死似乎也不容忽视。急性右心梗死通常也伴随着颈静脉充盈和肝大,这些与患者的目前状态相呼应。\n\n既然剧烈胸痛和CPK升高都是心肌梗死的强烈信号,再加上急性右心室梗死可能引发的低血压,这些都让我倾向于右心室的问题。这一切似乎指向右心室心肌梗死,特别是考虑到他的冠心病史。\n\n综上所述,虽然其他病症如心脏压塞或左心功能不全也可能解释一些症状,但结合所有表现和病史,急性右心室心肌梗死显得尤为合理。是的,我觉得这是最有可能的诊断。","Response": "根据患者的症状和病史,最有可能的诊断是急性右心室心肌梗死。患者有冠心病史,现在正经历急性剧烈胸痛,血液中CPK的显著升高表明有心肌受损。此外,颈静脉充盈和肝大,以及血压显著下降,这些都符合急性右心室心肌梗死的表现。尽管心脏压塞和心源性休克等情况也会出现类似症状,但结合患者的冠心病史及以上症状,急性右心室心肌梗死是更为合理的诊断。 建议立即进行心电图和超声心动图等检查以确认诊断,并尽快给予针对性治疗。"},{"Question": "该患儿于胸骨左缘第4~5肋间闻及柔和舒张期杂音,导管检查示右房血氧饱和度较上腔静脉明显增高。请问在此情况下,该患儿的心电图最可能出现什么样的变化?","Complex_CoT": "哦,小孩在胸骨左缘第4到5肋间能听到柔和的舒张期杂音,这提示可能存在心内的左向右分流。到底是哪种类型的心脏问题呢?从导管检查的结果来看,右房的血氧饱和度比上腔静脉明显高,说明右房有氧气丰富的血液渗入,这很可能是房间隔缺损 (ASD) 导致的,也就是说左房与右房之间有个洞。\n\n那么房间隔缺损会对心电图产生哪些影响呢?我们知道ASD 会让右心房和右心室的压力增加,长此以往,可能会导致右心室肥厚,这在心电图上应该会有一些特征表现吧。\n\n好的,那心电图上具体可能出现什么呢?因为右侧心房和心室的负担增加,电轴可能因此而向右偏移。对哦,这样一来,可能在右心导联上,比如V1导联,我们能看到R波增高,P波也可能比较宽大,表明右心房增大。\n\n总结一下,这个小孩的心电图很可能会表现为电轴右偏,且在V1导联中的R波增高。此外,P波宽大的情况也可能出现,这些迹象都在提示右心房和右心室的变化。\n\n不过我们需要仔细确认这些分析是否准确。根据房间隔缺损的心电图特征,我们需要考虑最常见的情况。典型来说,ASD的心电图包括电轴右偏和右束支传导阻滞(RBBB)或是不完全右束支传导阻滞(IRBBB)。\n\n当右心的负荷增加时,右束支传导阻滞会出现。在心电图上,这体现为V1导联中有个类似rSR'的波型,QRS波时间会比平时长些。\n\n还有一点就是电轴的右偏,ASD常导致电轴右偏,因为右心室负担过度。这种改变能在肢体导联的心电图上观察到。\n\n所以,综合来看,这个小孩的心电图可能会表现出电轴右偏,还会有不完全右束支传导阻滞(IRBBB),表现为V1导联的rSR'波型。这和房间隔缺损的典型特征是吻合的,也符合导管检查的结果。嗯,这样的结论是比较合理的。","Response": "该患儿的临床表现提示可能存在房间隔缺损(ASD)。在这样的情况下,ASD常导致右心房和右心室的压力负担增加,从而引起一些典型的心电图变化。最可能的心电图表现包括:\n\n1. **电轴右偏**:由于右心室负载增加,心电图上可能显示电轴向右偏移。\n\n2. **不完全右束支传导阻滞(IRBBB)**:在V1导联中可见rSR'波型,因为右心室增大和传导途径的改变,会表现为类似不完全性右束支传导阻滞的特征。\n\n这些心电图表现与房间隔缺损引起的右心房和右心室负担增加是相符的。"},{"Question": "患者出现大汗出、腹胀满、身重转动不灵活、食不知味、语言不利、心烦谵语、小便失禁、面部如蒙油垢、舌苔黄、脉浮滑等症状,应使用哪种中药方进行治疗?","Complex_CoT": "患者出现了这样的症状:大汗出、腹胀满、身重难以活动、食欲不振、语言迟缓、心烦意乱、谵语、小便失禁,面部好像蒙了层油,舌苔发黄,脉象浮滑,嗯,这些都在提示我们可能是湿邪造成的问题。\n\n仔细想想,湿热内蕴可能是原因之一,尤其是当湿邪困扰中焦的时候,会影响脾胃的运化功能,而且可能导致神志不清,一想到这,我觉得可能需要考虑化湿清热的办法。\n\n初步我想到温胆汤和二陈汤,这些都是治湿热的好方子,但根据身体发重,方子中的化湿重点要更突出才行。或许茵陈五苓散可以解决这类湿热并重的症状。\n\n不过,回头再想想,患者症状还包括心烦谵语,这表示热象也很明显,这么说来,得认真对待这些热症。这些情况下,用甘露消毒丹也是个选择,因为它能清热解毒,利湿化浊。\n\n可是,再梳理一下,甘露消毒丹主要是清热上焦用的。患者这么多湿热中焦、身重腹胀的问题,似乎还不完全对症。\n\n再看症状,体内湿气可能更重,比如食不知味、舌苔黄等。这种情况下,藿香正气散和平胃散可以考虑。特别是平胃散,帮助燥湿运脾、行气,能支持消除腹胀满这类湿阻问题。\n\n虽然想到平胃散,但患者的热症还不能忽视,大汗出、心烦、舌苔黄,这反馈热较重,所以我得想个更解热的方子,干脆再查查白虎汤吧!\n\n哦,对,白虎汤清热作用强,适合大汗出和烦渴谵语,结合心烦热重这些,看来这次建议用白虎汤确实更可靠。","Response": "根据患者的症状分析,考虑到患者的热象较重(心烦、谵语、大汗出、舌苔黄)以及湿阻中焦的表现(腹胀满、身重、食不知味、语言不利),在多种可能性中,白虎汤因其强效的清热作用,是一个较为适合的选项。白虎汤擅长清热解毒,尤其适合用在大汗出、热重心烦以及谵语等表现较为明显的情况下。结合患者现有的症状表现,建议使用白虎汤进行治疗。"},{"Question": "在患者视力骤降、神膏混浊、视衣脱离,伴随情绪急躁易怒、失眠多梦、耳鸣如潮、口苦、舌红苔黄、脉弦数的情况下,宜选用哪种中药方剂进行治疗?","Complex_CoT": "首先,患者的视力突然下降,这确实挺让人困扰的,还有神膏混浊和视衣脱离,明显是眼睛出了状况。然而,更让我感到意外的是患者还伴有情绪急躁易怒、耳鸣如潮、口苦、以及失眠多梦。这些症状并不是独立的,看起来像是某种整体状态的紊乱。\n\n嗯,情绪方面的问题,比如急躁易怒,真的很像肝有问题。中医里通常会想到肝气郁结或是肝火的上扰。嗓音上有点苦味,舌头也呈现红色而且苔黄,这进一步指向身体里有热,或者火比较旺。\n\n想到这里,我就感觉这个问题可能和肝火上炎或者肝阳上亢有很大关系。尤其是脉象显示弦数,真得引起重视了。肝火上炎的人脉象通常是这样的。\n\n那么,如果是这种肝火或者肝阳的问题,在中医药方中,龙胆泻肝汤倒是一个常用的选择。这个方子主要用来清肝火、泻湿热,很对路啊。\n\n经过一番思考,看样子这个患者确实比较适合用龙胆泻肝汤。尤其是他眼睛的问题和伴随的这些症状,刚好能通过清肝泄火来缓解。选择这个方子应该能达到不错的疗效。","Response": "在患者视力骤降、神膏混浊、视衣脱离,并伴有情绪急躁易怒、失眠多梦、耳鸣如潮、口苦、舌红苔黄、脉弦数的情况下,宜选用龙胆泻肝汤进行治疗。该方剂以清肝火、泻湿热为主,能够有效缓解患者的上述症状。"},{"Question": "如果患儿出现从眼睑开始的水肿,继而四肢甚至全身浮肿,来势迅速,伴有颜面肿胀明显,皮肤光亮压之凹陷即起,小便减少或尿血症状,并且伴随发热、恶风、肢体酸痛,舌苔薄白,脉象浮等症状,应选用哪个方剂进行治疗?","Complex_CoT": "哦,看看这个小患者的症状,眼睑浮肿开始,迅速扩展到全身,这种水肿来得真快。然后尿量减少,还可能尿血,这可有点糟糕,好像水液运化有问题啊。接着还有发热、恶风,肢体酸痛,舌苔薄白,脉象浮,听起来有点像外感风寒的症状呢。嗯,看来得从风水阻滞的角度来分析。风湿入表,水液就停滞在表面,真是麻烦,该怎么下手呢?\n\n想到传统方剂,祛风化湿,通利水道为主才对。最开始想到麻黄汤,它能发汗解表,但是又想到,它更适合单纯的风寒表证,没有考虑这个水肿表现啊。嗯,我们得换个思路。现在的重要任务是既要解表,缓解这个令人不快的水肿,又要解决小便问题。\n\n要同时针对表证和水肿,唔,那就不能只是普通的风寒表剂了,要不换思路看看防己黄芪汤?它针对风水互结,表虚又容易感外邪,还是不错的选择,对这个病例来说好像也有点贴合。不过啊,总感觉它的利水消肿可能不完全够,如果是兼顾更多的症状表现会更好。\n\n再往深处想想,还是觉得有点不对啊,尤其是解表和利水两个方向都要顾及。五苓散呢,为内停水湿而设计,对利尿消肿效果不错,它的双重作用似乎在这种情况也能发挥作用。但仔细一看,这还得考虑那些明显的表证,比如发热和恶风,五苓散可能缺乏足够的解表效果,还是得更深入地找找。\n\n对了,如果我们需要兼顾表证和水湿,本来要考虑既能解表,又能消肿的方子才好。想到麻黄连翘赤小豆汤,它不仅有麻黄,可以发散风寒,还加上了赤小豆,正可以利湿消肿。这样一来,似乎能更好地应对患者的这种水肿和表证同存的病症。\n\n嗯,麻黄连翘赤小豆汤的适应症中有兼有表证和水湿内停这一点。现在看来,用这个方剂来解决小患者的症状是个合理的选择,这样不就可以放心使用了吗?","Response": "针对患儿出现的从眼睑开始的迅速水肿,伴随小便减少或尿血,以及发热、恶风、肢体酸痛等症状,可以考虑使用麻黄连翘赤小豆汤。该方剂能够兼顾解表和利湿消肿,非常适合于表证和水湿内停同时存在的情况。这样既可以缓解表证比如发热、恶风,又能够有效消除水肿,还利于改善小便减少或尿血的症状。"} ]
六、插入数据
# 插入测试样本数据collection = client.collections.get(collection_name)with open("testdata.json",encoding="utf-8") as fr:data_objects = json.load(fr)print(data_objects)# 插入数据时手动传入向量for d in data_objects:vector_data = model.encode(d['Question']).tolist()collection.data.insert(properties=d,vector=vector_data)print(d)print(len(vector_data),vector_data)print("数据插入成功!")
七、对插入的数据进行查询
# # 查询向量query_text = "导管检查示右房血氧饱和度较上腔静脉明显增高"vector_data = model.encode(query_text).tolist()results = collection.query.near_vector(near_vector=vector_data,limit=3, # 返回最相似的 3 条数据# return_names=["Question"],return_properties=["Question"],return_metadata=MetadataQuery(distance=True))for o in results.objects:print(o.properties)print("Distance={}, Score={},Certainty={}".format(o.metadata.distance,o.metadata.score,o.metadata.certainty))# print(dir(o.metadata))
八、完整的代码
import json
import weaviate
from sentence_transformers import SentenceTransformer
from weaviate.auth import Auth
from weaviate.classes.query import MetadataQueryweaviate_api_key = "WVF5YsdfkYwhfasdfsX3dsfsddN8pkih" #根据自己的的docker进行设置
# 连接 Weaviate
client = weaviate.connect_to_local(host="127.0.0.1",port=8080,grpc_port=50051,auth_credentials=Auth.api_key(weaviate_api_key),
)meta = client.get_meta()
print("已加载模块:", meta["modules"])
print("客户端是否已连接数据库?",client.is_ready())try:model = SentenceTransformer(r"D:\MyDevelop\MOD\huggingface\baai\bge-reranker-v2-m3")# 创建一个名为my_collect的集合collection_name = "My_collect_2"client.collections.delete(collection_name)if collection_name not in client.collections.list_all(): # 判断是否存在,如果已存在就跳过class_obj = {"class": collection_name,"vectorizer": None,"vectorIndexConfig": {"distance": "cosine","efConstruction": 256, # 重点调整此参数"maxConnections": 64, # 每层最大连接数(影响图密度)"ef": 128 # 查询时动态调整},"properties": [{"name": "content", "dataType": ["text"]}]}client.collections.create_from_dict(class_obj)# 插入测试样本数据collection = client.collections.get(collection_name)with open("testdata.json",encoding="utf-8") as fr:data_objects = json.load(fr)print(data_objects)# 插入数据时手动传入向量for d in data_objects:vector_data = model.encode(d['Question']).tolist()collection.data.insert(properties=d,vector=vector_data)print(d)print(len(vector_data),vector_data)print("数据插入成功!")## # 查询向量query_text = "导管检查示右房血氧饱和度较上腔静脉明显增高"vector_data = model.encode(query_text).tolist()results = collection.query.near_vector(near_vector=vector_data,limit=3, # 返回最相似的 3 条数据# return_names=["Question"],return_properties=["Question"],return_metadata=MetadataQuery(distance=True))for o in results.objects:print(o.properties)print("Distance={}, Score={},Certainty={}".format(o.metadata.distance,o.metadata.score,o.metadata.certainty))# print(dir(o.metadata))finally:# 关闭连接client.close()
问题回顾:
在探索过程中,遇到了一些问题,耗费较多时间始终未能解决,后来灵感来袭或幸运偶降才得以解决。这些问题犹如学习的大坑,一不小心容易踩到。现摘记如下,方便日后跳坑:
1、Weaviate因为客户端的升级,网上收到的一些函数或者写法,已经做了调整。例如V4里面已经没有client.schema的写法了。现在已经改成了client.collections。
2、Weaviate默认没有设置text2vec模块,需要手动指定,但是指定后又需要配置相关参数,网上搜索到的很多举例代码,在如何设置text2vec模块上没细说,或许是因为每一种text2vec,都有不同的配置方式,后来不得不查官网才了解到方法。最坑的是,代码里设置text2vect时,是用text2vec_transformers 这种格式,但是在docker配置时,是用text2vec-transforms这种格式(注意横杠),一不小心,就会弄错,导致无法加载模块。
3、在使用weaviate调用ollama的text2vec时,通过postman调用ollama的embed可以成功取得返回值,但是weaviate总是报500错误,说是拒绝服务,一直没有找到原因。
4、关于语义相似度,主要有余弦算法、L2欧式距离算法、汉明算法,点积算法等等。其中文本相似性,用的较多的是余弦算法。weaviate默认也用了余弦算法。因此,当你在搜索的时候,发现搜索到的内容第一条,不是关键字完全匹配的内容时,也就不稀奇了。就像【4,5,6】和【4,8,12】两个向量,哪个跟【1,2,3】更相似,直觉可能会影响你的判断,但这个是余弦相似性的重要特点。
5、Dify安装过程中,默认的weaviate安装,没有把端口映射出来,无法直接访问。需要修改配置重新启用。如果直接把容器删掉并重新安装,会导致dify里面的知识库无法连接到向量数据库。初步估计原因是,初始安装dify时,是用docker compse 批量安装的,删除后用了docker run进行安装,docker run里面把目录映射遗漏了。这里写一下,提醒要小心。