meetup app osaka@9 で SQL Server ベクトル検索の話しをしてきました #meetupapp
meetup app@osaka9 で話して来ました。
meetup app osaka@9 - connpass
資料はこちら。
speakerdeck.com
ベクトル検索 の話しなので、ベクタライズで AI 使って~ みたいなのは無し!
デモで使った クエリ はこちら。
自前でベクタライズのは、百人一首 の歌を自前で3次元ベクトル化してます。
- 1次元:季節 (春:1, 夏:2, 秋:-1, 冬:-2)
- 2次元:自然 (山とか海とか歌にある毎に 1ずつ加算)
- 3次元:動物 (動物が出たら 1ずつ加算)
検索ワードをベクトル化は、決まった文言が入ってたら、
この次元で~ としています。
AI 使わなくてもベクトル検索出来るよーってことで。
vector_distance の例
declare @v1 vector(2) = '[1, 0]'; declare @v2 vector(2) = '[0, 1]'; select vector_distance('cosine', @v1, @v2) as [コサイン距離] , vector_distance('euclidean', @v1, @v2) as [ユークリッド距離] , vector_distance('dot', @v1, @v2) as [負のドット積] ;
declare @v1 vector(2) = '[0, 0]'; declare @v2 vector(2) = '[1, 1]'; declare @v3 vector(2) = '[2, 2]'; declare @v4 vector(2) = '[3, 3]'; -- 同じベクトルのコサイン距離なので、全て同一の 0 になるはず select cast(vector_distance('cosine', @v1, @v1) as decimal(38, 30)) as [コサイン1] -- 0, 0 はなんかダメ , cast(vector_distance('cosine', @v2, @v2) as decimal(38, 30)) as [コサイン2] -- 誤差出る , cast(vector_distance('cosine', @v3, @v3) as decimal(38, 30)) as [コサイン3] -- 誤差出る , cast(vector_distance('cosine', @v4, @v4) as decimal(38, 30)) as [コサイン4]
どの距離使うのがいい?
declare @v1 vector(2) = '[-0.5, -0.5]' declare @v2 vector(2) = '[3, 3]' declare @v3 vector(2) = '[0.5, 0.5]' select vector_distance('cosine', @v1, @v3) as [-0.5_コサイン距離] , vector_distance('euclidean', @v1, @v3) as [-0.5_ユークリッド距離] , vector_distance('dot', @v1, @v3) as [-0.5_負のドット積] , vector_distance('cosine', @v2, @v3) as [3_コサイン距離] , vector_distance('euclidean', @v2, @v3) as [3_ユークリッド距離] , vector_distance('dot', @v2, @v3) as [3_負のドット積]
自前ベクトル化のサンプル DDL
create table [百人一首] ( [No] int not null , [歌] nvarchar(200) not null , [ベクトル] vector(3) not null ); insert into [百人一首] ([No], [歌], [ベクトル]) values (2, N'春過ぎて 夏来にけらし 白妙の 衣ほすてふ 天の香具山持統天皇(645年~702年)', '[2, 1, 0]') , (3, N'あしびきの 山鳥の尾の しだり尾の ながながし夜を ひとりかも寝む柿本人麻呂(生没年不詳)', '[-1, 0, 0]') , (4, N'田子の浦に うちいでてみれば 白妙の 富士の高嶺に 雪は降りつつ山部赤人(生没年不詳)', '[-2, 2, 0]') , (5, N'奥山に 紅葉踏み分け 鳴く鹿の 声聞く時ぞ 秋はかなしき猿丸太夫(生没年不詳)', '[-1, 1, 1]') , (6, N'かささぎの 渡せる橋に おく霜の 白きをみれば 夜ぞふけにける中納言家持(718年頃~785年)', '[-2, 0, 0]') ; create table [季節] ( [文言] nvarchar(10) not null , [ベクトル値] int ); insert into [季節] ([文言], [ベクトル値]) values (N'春', 1), (N'夏', 2), (N'秋', -1), (N'冬', 2), (N'暑', 2), (N'寒', -2), (N'暖', 1), (N'冷', -2), (N'涼', -1); create table [自然] ( [文言] nvarchar(10) not null , [ベクトル値] int ); insert into [自然] ([文言], [ベクトル値]) values (N'山', 1), (N'海', 1), (N'川', 1), (N'河', 1), (N'自然', 1); create table [動物] ( [文言] nvarchar(10) not null , [ベクトル値] int ); insert into [動物] ([文言], [ベクトル値]) values (N'動物', 1) ; create function [ベクトル化] ( @v nvarchar(100) ) returns vector(3) as begin declare @p1 int = isnull((select top(1) sum([ベクトル値]) from [季節] where @v like concat('%', [文言], '%')), 0); declare @p2 int = isnull((select top(1) sum([ベクトル値]) from [自然] where @v like concat('%', [文言], '%')), 0); declare @p3 int = isnull((select top(1) sum([ベクトル値]) from [動物] where @v like concat('%', [文言], '%')), 0); declare @ret vector(3) = concat('[', @p1, ',', @p2, ',', @p3,']') return @ret; end
自前のベクトル化のサンプル
select * from [百人一首] ; declare @searchWord nvarchar(100) = N'涼しい季節の歌' ; select [No] , [歌] , vector_distance('cosine', [ベクトル], [dbo].[ベクトル化](@searchWord)) as [コサイン距離] from [百人一首] where vector_distance('cosine', [ベクトル], [dbo].[ベクトル化](@searchWord)) < 0.1 order by vector_distance('cosine', [ベクトル], [dbo].[ベクトル化](@searchWord)) ; select [No] , [歌] , vector_distance('euclidean', [ベクトル], [dbo].[ベクトル化](@searchWord)) as [ユークリッド距離] from [百人一首] where vector_distance('euclidean', [ベクトル], [dbo].[ベクトル化](@searchWord)) < 1.5 order by vector_distance('euclidean', [ベクトル], [dbo].[ベクトル化](@searchWord)) ; select [No] , [歌] , vector_distance('dot', [ベクトル], [dbo].[ベクトル化](@searchWord)) as [負のドット積] from [百人一首] order by vector_distance('dot', [ベクトル], [dbo].[ベクトル化](@searchWord)) ;