Bo's Oracle Station

【博客文章2025】Oracle Database 23ai:AI Vector Search笔记与实验7---利用自编的Embedding函数实现中文相似性查询

2025-2-2 20:09| 发布者: admin| 查看: 93| 评论: 0|原作者: Bo Tang

摘要: 本博客介绍利用自编的Embedding函数实现中文相似性查询。同时比较了相似性查询和普通的字符模糊查询的巨大不同。具体实现步骤包括:准备数据、编写存储过程完成数据向量化、利用自编的Embedding函数生成嵌入向量和利用自编的Embedding函数实现中文相似性查询。
【博客文章2025】Oracle Database 23ai:AI Vector Search笔记与实验7---利用自编的Embedding函数实现中文相似性查询


Author: Bo Tang

1. 准备数据:

    本博客使用这两篇博客中的实验环境。加上这篇原创的,由朋友于2006年创作的(从未在互联网上流传的)小游记《老荒游福州》fz.pdf,并将其加载到t1表中:

exec pack_blob.insert_blob(18,'DIR1','fz.pdf');

    接下来,要利用《AI Vector Search笔记与实验6》中编写的通用函数为库内数据生成向量。

2. 编写存储过程完成数据向量化:

    创建一个新表来存储非结构化的数据chunks和相关的嵌入向量。这个表将引入一个叫做vector类型的列:

create table t1chunksollama (doc_id number, chunk_id number, chunk_data clob, chunk_embedding vector);

    
    首先插入数据(使用insert语句从t1表的data列读取PDF文档,转换这些PDF文档为文本),然后将文本分块成数据chunks,最后为每一个数据chunk使用《AI Vector Search笔记与实验6》中编写的通用函数为库内数据生成向量
    这些事情要通过编写一个存储过程来完成:dbms_vector_chain包中的utl_to_text将PDF数据转换成文本;utl_to_chunks将文本分块;func_text_input_ollama为每一个文本分块生成嵌入向量:

create or replace procedure proc_ins_t1chunksollama(p_id number)
is
begin
 insert into hr.t1chunksollama
  SELECT D.id id,
   JSON_VALUE(C.column_value, '$.chunk_id') AS id,
   JSON_VALUE(C.column_value, '$.chunk_data') AS txt,
   func_text_input_ollama(
                          replace(
                           replace(
                            replace(
                             replace(
                              replace(
                               replace( 
                                replace(
                                 replace( 
                                  replace(
                                   JSON_VALUE(C.column_value, '$.chunk_data'),chr(10),' '
                                         ),chr(34),' '
                                        ),chr(39),' '
                                       ),chr(123),' ' 
                                      ),chr(125),' '
                                     ),chr(92),' '
                                    ),chr(47),' '
                                   ),chr(91),' '
                                  ),chr(93),' '
                                           )
                                   )
 FROM hr.t1 D,
            dbms_vector_chain.utl_to_chunks(dbms_vector_chain.utl_to_text(D.data),
                                  JSON('{ "by": "words",                                                              
                                          "split": "recursively",
                                          "language" : "simplified chinese",
                                          "normalize": "all"
                                                    }'
                                                  )
                                  ) C
 where D.id=p_id;
 commit;

end;
/

    为了保证生成向量成功,必需逐层把文本块中的chr(10)、chr(34)、chr(39)、chr(123)、chr(125)、chr(92)、chr(47)、chr(91)和chr(93)替换成' '。以下给出这些ASCII字符对照表:

chr(10)

 '\n' (new line) 

chr(34)

 "

chr(39)

 '

chr(123)

{

chr(125)

 }

chr(92)

 \  '\\'

chr(47)

 /

chr(91)

 [

chr(93)

 ]


    这些字符都是JSON保留字,所以必需被替换成空格。
    另外请注意:在utl_to_chunks进行数据分块时,传递的JSON参数是: "language" : "simplified chinese",这是因为t1表中的PDF都是中文文本。而func_text_input_ollama利用Ollama的bge-m3大语言模型支持中文向量化

3. 利用自编的Embedding函数生成嵌入向量:

    执行本文第2节中编写的过程proc_ins_t1chunksollama:

 exec proc_ins_t1chunksollama(18);

    重复以上步骤,再向t1表(之后用func_text_input_ollama)加载大量其他pdf数据并向量化它们,以避免案例的个例化和不具代表性:

 select count(*) from t1chunksollama;

COUNT(*)
 51883

    检查是否都生成了向量:

 select  * from t1chunksollama where  chunk_embedding is null;
无结果集

    说明使用
《AI Vector Search笔记与实验6》中的自编函数生成向量都成功。

4. 利用自编的Embedding函数实现中文相似性查询:

4.1 普通的字符模糊查询不返回任何结果:

select doc_id, chunk_data from hr.t1chunksollama  where  chunk_data like '%老荒游福州的所有景点%';
无结果集

4.2 创建“内存中邻居图向量索引”:
    鉴于t1chunksollama中有5万多条向量数据,为了加速查询,我们来创建内存中邻居图向量索引”:

create vector index t1_hnsw_idx on t1chunksollama(chunk_embedding)
organization inmemory neighbor graph
distance COSINE
with target accuracy 95 ;

    注意:创建了内存中邻居图向量索引”的表是无法再进行DML操作的。

BEGIN proc_ins_t1chunksollama(19); END;

*
第 1 行出现错误:
ORA-51928: 不支持对具有内存中邻居图向量索引的表使用数据操纵语言 (DML)。 ORA-06512: 在
"HR.PROC_INS_T1CHUNKSOLLAMA", line 5
ORA-06512: 在 line 1
帮助:https://docs.oracle.com/error-help/db/ora-51928/

    如果要再进行DML操作,那么需要先删除内存中邻居图向量索引”:

drop index t1_hnsw_idx;

4.3 实现中文相似性查询:

 select doc_id, chunk_data from hr.t1chunksollama
 order by vector_distance(chunk_embedding , func_text_input_ollama('老荒游福州的所有景点'), cosine)
 fetch first 25 rows  only;


DOC_IDCHUNK_DATA
18老荒游福州 (2006.1.29 - 2.3) 大年初一:北京-福州,华林寺-西湖-福建省博物馆-三坊七巷 狗年的第一顿饭是在海航的飞机上吃了一盒饺子。中午,从机场
18纪念馆没有游客留言簿。但我真想说一句: 福州出了个林则徐! 下午还去了两座庙 - 归元寺和地藏寺,都是免费。归元寺里有一 尊古代铁佛,约40吨重,也不知何人所铸。来寺进香的主要是本地
18大年初五:白马双溪,福州:林则徐纪念馆-归元寺-地藏寺 今天经历了三件讨厌事,对福建的印象有跌幅。 第一件:从青云山回永泰县城,摩的司机开价要20元。到达后,
18票五元,看来福州不是典型的旅游城市,不以门票宰客。公园旁边是 船政学堂和造船厂故址。1866年,闽浙总督左宗棠奏请在福州办船 政。船政初始,左宗棠调任陕甘总督,赴任前,力荐沈葆桢总理船政
18回到宾馆用温泉砸了砸。想到福州小吃甜、油、过分细腻,不利 于体能恢复。在胃的建议下,去找回民吃了两碗拉面。晚上逛了台江 路步行街和榕城古街,没啥意思,这种市面,全国都大同小异。我出
18乘大巴到福州市区,入住于山宾馆。于山宾馆位于福州的黄金地段, 背依于山,面朝五一广场,闹中取静。我选择的标间位于最高的四层, 朝山,可以洗温泉,观瀑布。过年吗,奢侈一把,195元。
18淡清静。要是在福州长住,我还真打算带上几本闲书,入此山门挂单 几日,往自己的心里走一遭。 晚饭吃了传说中的沙县小吃,原料和味道都平常,可取之处就是 便宜。 大年初六:于山,福州-北京
18不如人,迂腐颓势的文化未尝不也是败因之一。 唏嘘之后,回到福州,于天色将晚之时登上乌山。福州小山多, 市民好福气。老年人爬山,找个石桌打麻将;年轻人爬山,找个石凳
18寺内著名的素面现称"平安发财面"。我见用料普通,又不是非要发 财不可,就下山去马尾了。好在于山宾馆的早餐有各式福州小吃,我 塞得很饱。 一直以为马尾是海港,到了才发现原来还没出闽江。罗星公园门
18谈恋爱。我饿了,下山觅食,吃了雪菜光饼、花生汤、竹筒蛋羹扇贝 等等。 大年初三:闽侯十八重溪-金山寺 一早去客运西站乘中巴到闽侯南屿,下车一打听,才知十八重溪 在下一个镇 -
18生活的人,不仅字写得极好,还爱研究水果,著有《荔枝谱》。品茶 也很在行,著有《茶录》。老蔡还是一位造桥专家,首创了流线型桥 墩,即科学,又美观。 福州是林则徐的出生地,是左宗棠客死的他乡。关于林则徐,我
18定和其他三人拼车打的回福州。在福州西站下车后,司机立刻开车狂 奔,我立刻意识到他找给我的是一张五十的假币。他完全是故意的, 真想薅丫头发往车上撞。 第三件:本来觉得于山宾馆服务很好,但此番回来,住了188的
18我面朝瀑布喊:"有没有女鬼,有没有女鬼?" 自然,保持她一贯的沉默,因为她从不承诺。 沐浴完毕,唱着山歌归去。由于景区封闭,沿公路走了很久,才 打到摩的。至南通,换乘客车回福州西站。又去了距此地不远江中的
18大年初二:鼓山白云洞-涌泉寺-马尾罗星公园-乌山 听说白云洞山高路远,就去看看。在咨询了公交售票员之后,于 下院前两站的远洋下车,花四块钱打摩的,至一村口。司机指着公厕
18的白马山庄。春节期间,标间涨到198一天。我开了一间,条件很一 般,所幸热水器很大。仔细研究了一下门票:四个景区,每个单独售 票25,学生票15;任意两个景区联票40。我后来花55元游遍了四
18金山寺。 木船摆渡过去,加门票共收费两元。金山寺极小,置于江中石上, 惟一僧、一塔、一樟、一榕,两进院落而已。前院供妈祖,后院供西 方三圣。暮霭沉沉,闽江东去,逝者如斯。
18是到了郊县,要格外防备存心使坏的出租和摩的。我想,如果带着一 个家庭生活,福州实在是个宜居的城市。但如果是一个人吃饱就全家 不饿了,住在福州,或许会感到不够痛快。
18来他们是四川来福建打工的,相约到此旅游。我发现,凡是游客相对 稀少的景区,人与人往往相当友善。 两位好人去追赶他们的同伴,我独自上行,逐一欣赏每一出瀑布。
9乃衮宦游憩之地,创有凉亭,雕栏画栋,极其华丽。壁间悬⼤家名笔,⼏上列稀世奇珍,佳联掇画,⽿⽬繁华,⼤额标题古今坟典,诚⼈间之蓬 岛,凡世之⼴寒也。⽣每与端游玩其间,或题咏,或琴棋,留连光景,取乐不⼀。
18事务。沈葆桢是林则徐的女婿,他后来赶走过侵台的日人,还对台湾 的开发贡献很大。 公园面朝马尾海战战场。我登上罗星塔观望,以江面作为战场, 过于狭窄,不利于进攻的一方。况且,福建水师的三艘军舰战前已经
18参照一张简易的地图,步行经西湖公园去省博物馆。西湖岸上游 人如织,博物馆里倒颇清静。就布展来说,淡化了阶级斗争,突出了 传统文化。闽籍的历史名人中,蔡襄给我印象较深。因为他是个热爱
18却要40元,说是返程费用。我说,那你应该事先和我讲清楚,这是 你的不对了。念十多公里路也不近,又给了他10元。 第二件:此事最为可恶。因永泰至福州的客车排队数百人,我决
12去。那个森林太奇怪了,人一走进似乎被下了迷药,脑袋都昏沉起来。 " " 我走过两次,但走到一半,就迷路了。上次跟育走过一次,结果转到樱花林这边来了。我们明明没有转弯。 " 我想起上次的
18翻山经小鼓、大鼓、观音掌,下行很远至涌泉寺。鼓山各景点相 距甚远,显得支离破碎。涌泉寺规模不小,咋说也比少林寺大,门票 三元。建寺虽早,但造像的配置和模样皆为近制。烧香祈福的人很多。
12感觉整个人是在一个立体感十足的空间走着,入眼的除了乾枯的樱花树还是樱花树,似乎整个树林都被樱花树埋没了。


    基本上,结果集中所有查出的相似性文本都出自18号文档(小游记《老荒游福州》),结果非常令人满意。
    以上代码中的“vector_distance(chunk_embedding , func_text_input_ollama('老荒游福州的所有景点'), cosine)”,代表两个向量之间距离比较的依据是“cosine”,这是默认值。其他的比较依据还有(使用不同的比较依据,结果集会略有不同):
    DOT:计算两个向量的负向点积。
    EUCLIDEAN:也称为L2距离,计算两个向量之间的欧几里德距离。
    EUCLIDEAN_SQUARED:也称为L2_SQUARED,是没有取平方根的EUCLIDEAN。
    HAMMING:通过计算两个向量之间维度数目的不同,来计算距离。
    JACCARD:计算JACCARD距离。查询中使用的两个向量必须是二进制向量。

路过

雷人

握手

鲜花

鸡蛋

QQ|手机版|Bo's Oracle Station   

GMT+8, 2025-2-22 16:52 , Processed in 0.039419 second(s), 21 queries .

返回顶部