rabbit-slide-kou-postgresql-conference-2015 2015.11.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,661 @@
1
+ = PGroongaの実装
2
+
3
+ : subtitle
4
+ (('note:ぴーじーるんがのじっそう'))
5
+ : author
6
+ 須藤功平
7
+ : institution
8
+ 株式会社クリアコード
9
+ : content-source
10
+ PostgreSQLカンファレンス2015
11
+ : date
12
+ 2015-11-27
13
+ : allotted-time
14
+ 40m
15
+ : theme
16
+ .
17
+
18
+ = (建前の)目的
19
+
20
+ PostgreSQLのamindexを説明
21
+
22
+ = 方法
23
+
24
+ PGroongaの実装を紹介\n
25
+ (('note:PGroongaはamindexとして実装されているため'))\n
26
+ (('note:ただし、ヒントだけなので詳細はPGroongaのソースを参照'))\n
27
+ (('note:https://github.com/pgroonga/pgroonga'))
28
+
29
+ = 本当の目的
30
+
31
+ PGroongaの自慢
32
+
33
+ = PGroongaとは
34
+
35
+ amindexの一種
36
+
37
+ = amindex
38
+
39
+ 索引の実装を\n
40
+ PostgreSQLに\n
41
+ 追加する仕組み
42
+
43
+ = amindexの使い方
44
+
45
+ # coderay sql
46
+ CREATE INDEX name ON table
47
+ USING pgroonga (column);
48
+
49
+ (('tag:center'))
50
+ 組み込みの索引と同じ\n
51
+ ((({USING}))を指定するだけ)
52
+
53
+ = PGroongaの提供機能
54
+
55
+ 索引を使った\n
56
+ ((*超高速な*))\n
57
+ 全文検索機能
58
+
59
+ = PostgreSQLと全文検索
60
+
61
+ 課題あり
62
+
63
+ = PostgreSQLと全文検索1
64
+
65
+ # coderay sql
66
+ CREATE INDEX name ON table
67
+ USING gin (to_tsvector('english', column));
68
+ SELECT * FROM table
69
+ WHERE to_tsvector('english', column) @@ '...';
70
+
71
+ (('tag:center'))
72
+ 組み込みの全文検索機能\n
73
+ 日本語非対応\n
74
+ (('note:http://www.postgresql.org/docs/current/static/textsearch.html'))
75
+
76
+ = PostgreSQLと全文検索2
77
+
78
+ # coderay sql
79
+ CREATE INDEX name ON table
80
+ USING gin (column gin_trgm_ops);
81
+ SELECT * FROM table
82
+ WHERE column % '...';
83
+
84
+ (('tag:center'))
85
+ contrib/pg_trgm\n
86
+ 日本語非対応\n
87
+ (('note:http://www.postgresql.org/docs/current/static/pgtrgm.html'))
88
+
89
+ = PostgreSQLと全文検索
90
+
91
+ 日本語非対応
92
+
93
+ = PGroongaとPostgreSQL
94
+
95
+ 日本語対応!
96
+
97
+ = PGroongaを使う
98
+
99
+ # coderay sql
100
+ CREATE INDEX name ON table
101
+ USING pgroonga (column);
102
+ SELECT * FROM table
103
+ WHERE column @@ '全文検索';
104
+
105
+ (('tag:center'))
106
+ 日本語対応!
107
+
108
+ = しかも速い!
109
+
110
+ = ヒット数と検索時間
111
+
112
+ # RT
113
+ delimiter = [|]
114
+
115
+ ヒット数 | 検索時間
116
+
117
+ 368 | 0.030s((' '))
118
+ 17,172 | 0.121s((' '))
119
+ 22,885 | 0.179s((' '))
120
+ 625,792 | 0.646s(*)
121
+
122
+ (('note:(*) work_memを10MBに増やしている'))
123
+
124
+ (('tag:center'))
125
+ データ:Wikipedia日本語版\n
126
+ (('note:約184万レコード・平均サイズ約3.8KB'))\n
127
+ (('note:詳細:http://www.clear-code.com/blog/2015/5/25.html'))
128
+
129
+ = 検索時間:比較
130
+
131
+ # RT
132
+ delimiter = [|]
133
+
134
+ ヒット数 | PGroonga | pg_bigm
135
+
136
+ 368 | 0.030s(!) | 0.107s((' '))
137
+ 17,172 | 0.121s(!) | 1.224s((' '))
138
+ 22,885 | 0.179s(!) | 2.472s((' '))
139
+ 625,792(*) | 0.646s((' ')) | 0.556s(!)
140
+
141
+ (('note:(*) 他は検索語が3文字以上でこれだけ2文字'))
142
+
143
+ (('tag:center'))
144
+ PGroongaは安定して速い!
145
+
146
+ = なぜ速いのか
147
+
148
+ バックエンドが\n
149
+ 外部の本格的な\n
150
+ 全文検索\n
151
+ ライブラリー
152
+
153
+ = amindexでのポイント
154
+
155
+ * (({_PG_init()}))
156
+ * ライブラリーを初期化
157
+ * (({on_proc_exit()}))
158
+ * 後始末
159
+
160
+ = 全文検索ライブラリー
161
+
162
+ Groonga
163
+
164
+ = Groonga
165
+
166
+ ((*本格的な*))\n
167
+ 全文検索\n
168
+ エンジン\n
169
+ (('note:サーバーとしてもライブラリーとしても使える'))
170
+
171
+ = 本格的な例1
172
+
173
+ (('tag:center'))
174
+ 長い文書でも検索性能が落ちない
175
+
176
+ (('tag:margin-top * 2'))
177
+ この特徴が有用なサービス例:
178
+
179
+ * Wiki
180
+ * イメージ:Wikipedia
181
+ * ドキュメント検索
182
+ * イメージ:ファイルサーバー検索
183
+
184
+ = 長い文書でも速い理由
185
+
186
+ ((*完全*))\n
187
+ 転置索引
188
+
189
+ = 転置索引
190
+
191
+ * 完全:位置情報あり
192
+ * Groonga
193
+ * 無印:位置情報なし
194
+ * GIN
195
+ * Groonga(('note:(必要なければ入れないことができる)'))
196
+
197
+ = 転置索引の違い
198
+
199
+ # image
200
+ # src = images/inverted-index.svg
201
+ # relative_height = 100
202
+
203
+ = 索引での検索の違い
204
+
205
+ # image
206
+ # src = images/search-with-inverted-index.svg
207
+ # relative_height = 100
208
+
209
+ = 検索速度の違い
210
+
211
+ * 完全転置索引:安定して速い
212
+ * 索引だけで検索完了
213
+ * 転置索引:速さが安定しない
214
+ * 索引での検索+全件スキャン
215
+ * 候補文書が多い・長い→遅くなる
216
+
217
+ = amindexでのポイント
218
+
219
+ * 全件スキャンを無効にする
220
+ * (({scan->xs_recheck = false}))
221
+ * (({tbm_add_tuples(..., false)}))
222
+
223
+ = 本格的な例2
224
+
225
+ (('tag:center'))
226
+ 常時更新・常時検索に強い
227
+
228
+ (('tag:margin-top * 2'))
229
+ この特徴が有用なサービス例:
230
+
231
+ * SNS
232
+ * イメージ:Twitter
233
+ * ナレッジ共有サービス
234
+ * イメージ:Qiita・teratail
235
+
236
+ = 常時更新・検索に強い?
237
+
238
+ 更新中も\n
239
+ 参照性能が\n
240
+ 落ちない
241
+
242
+ = 落ちない理由
243
+
244
+ 更新時に\n
245
+ 参照ロックなし
246
+
247
+ = 参照ロック
248
+
249
+ 獲得したら\n
250
+ 他の処理は\n
251
+ 参照不可になる\n
252
+ ロック
253
+
254
+ = GINと更新と参照
255
+
256
+ # image
257
+ # src = images/read-while-write-gin.svg
258
+ # relative_height = 95
259
+
260
+ = Groongaと更新と参照
261
+
262
+ # image
263
+ # src = images/read-while-write-groonga.svg
264
+ # relative_height = 95
265
+
266
+ = PGroongaと更新と参照
267
+
268
+ # image
269
+ # src = images/read-while-write-pgroonga.svg
270
+ # relative_height = 95
271
+
272
+ = 参照ロックフリーの実現
273
+
274
+ # image
275
+ # src = images/reference-lock-free-idea.svg
276
+ # relative_height = 100
277
+
278
+ = amindexでのポイント
279
+
280
+ * (({Lock*()}))(('note:(*)'))を呼ばない\n
281
+ (('note:(*) PostgreSQL提供のロックAPI'))
282
+ * 呼ぶとGroongaの参照ロックフリーの有意性を殺してしまう
283
+
284
+ = 本格的な例3
285
+
286
+ (('tag:center'))
287
+ 継続的な更新に強い
288
+
289
+ (('tag:margin-top * 2'))
290
+ この特徴が有用なサービス例:
291
+
292
+ * SNS
293
+ * イメージ:Twitter・Facebook
294
+ * チャット
295
+ * イメージ:Slack
296
+
297
+ = 継続的な更新に強い?
298
+
299
+ * 間欠的な性能劣化がない
300
+ * 更新も検索も
301
+ * GINは両方ある
302
+ * (({FASTUPDATE}))を無効にしていない場合
303
+
304
+ = 間欠的性能劣化がない理由
305
+
306
+ * 常に最新ポスティングリストを\n
307
+ 維持しているから
308
+ * 更新負荷が高くならない対策入り\n
309
+ (('note:https://github.com/groonga/groonga/wiki/Memo'))
310
+ * GINは維持をサボって高速化
311
+ * サボったつけを払うときに性能劣化
312
+ * 例:検索時・更新が溜まりすぎた時
313
+
314
+ = 本格的な例4
315
+
316
+ (('tag:center'))
317
+ 索引の作り直しが速い
318
+
319
+ (('tag:margin-top * 2'))
320
+ この特徴が有用なケース:
321
+
322
+ * ダンプのリストア
323
+ * サービス復旧
324
+
325
+ = 索引作成
326
+
327
+ # RT
328
+ delimiter = [|]
329
+
330
+ 元データの\nロード時間 | 索引\n作成時間
331
+
332
+ 16分31秒 | 25分37秒
333
+
334
+ (('tag:center'))
335
+ データ:Wikipedia日本語版\n
336
+ (('note:約184万レコード・平均サイズ約3.8KB'))\n
337
+ (('note:詳細:http://www.clear-code.com/blog/2015/5/25.html'))
338
+
339
+ = 索引作成:比較
340
+
341
+ # RT
342
+ delimiter = [|]
343
+
344
+ PGroonga | pg_bigm
345
+
346
+ 25分37秒 | 5時間56分15秒
347
+
348
+ (('tag:center'))
349
+ pg_bigmより約14倍速い!
350
+
351
+ = 速い理由
352
+
353
+ ((*静的*))\n
354
+ 索引構築を\n
355
+ サポート
356
+
357
+ = 索引構築方法
358
+
359
+ * ((*動的*))索引構築
360
+ * 構築中も完了した分は検索可能
361
+ * 即時反映可・一括登録不向き
362
+ * ((*静的*))索引構築
363
+ * 構築完了まで使えないが速い\n
364
+ (('note:(処理時間は入力に比例。指数関数的ではない。)'))
365
+ * 即時反映不可・一括登録向き
366
+
367
+ = SQLの違い
368
+
369
+ # coderay sql
370
+ -- 動的索引構築
371
+ CREATE INDEX ...;
372
+ INSERT ...;
373
+ -- 静的索引構築
374
+ INSERT ...;
375
+ CREATE INDEX ...;
376
+
377
+ = amindexでのポイント
378
+
379
+ * (({aminsert()}))
380
+ * 動的索引構築を実装
381
+ * (({ambuild()}))
382
+ * 静的索引構築を実装
383
+
384
+ = 速い理由のまとめ
385
+
386
+ * 索引だけで検索可能
387
+ * 更新中も検索可能
388
+ * 間欠的な性能劣化なし
389
+ * 静的索引構築をサポート
390
+
391
+ = 速さ以外の利点1
392
+
393
+ 便利な独自機能
394
+
395
+ = 独自機能1
396
+
397
+ 見慣れた\n
398
+ クエリー言語
399
+
400
+ = 例
401
+
402
+ # coderay sql
403
+ body @@ 'PostgreSQL OR MySQL -Oracle'
404
+
405
+ * Web検索エンジン互換
406
+ * →ユーザーの入力をそのまま使える
407
+ * デフォルトAND
408
+ * OR・-(除外)あり
409
+
410
+ = 独自機能2
411
+
412
+ 配列+全文検索
413
+
414
+ = 例
415
+
416
+ # coderay sql
417
+ CREATE TABLE logs (hosts text[]);
418
+ INSERT INTO logs
419
+ VALUES (Array['web', 'db']);
420
+ CREATE INDEX index ON logs
421
+ USING pgroonga (hosts);
422
+ SELECT * FROM logs
423
+ WHERE hosts @@ '各ホスト名を全文検索';
424
+
425
+ = 独自機能3
426
+
427
+ JSON+全文検索
428
+
429
+ = 例
430
+
431
+ # coderay sql
432
+ INSERT INTO logs (record)
433
+ VALUES ('{"host": "ダウンホスト"}'),
434
+ ('{"message": "シャットダウン"}');
435
+ SELECT * FROM logs
436
+ WHERE record @@ 'string @@ "ダウン"'
437
+ -- record
438
+ -- ----------------------------
439
+ -- {"host": "ダウンホスト"}
440
+ -- {"message": "シャットダウン"}
441
+
442
+ (('tag:center'))
443
+ JSON内の全テキストから全文検索
444
+
445
+ = 独自機能4
446
+
447
+ ノーマライザー
448
+
449
+ = ノーマライザー
450
+
451
+ * 文字を正規化するモジュール
452
+ * 表記の違いを吸収できる
453
+ * (('wait'))アルファベット:全部小文字
454
+ * (('wait'))ひらがな・カタカナ:全部全角
455
+ * (('wait'))㍉→ミリ
456
+ * (('wait'))UnicodeのNFKCベース
457
+
458
+ = 独自機能5
459
+
460
+ トークナイザー
461
+
462
+ = トークナイザー
463
+
464
+ * キーワード切り出しモジュール
465
+ * クエリーに指定できる\n
466
+ キーワードを調整
467
+ * 例:すもも|も|もも|も
468
+
469
+ = デフォルト:可変長Ngram
470
+
471
+ * 英語:字種区切り
472
+ * 例:Hello|World|!!!
473
+ * Bigramだとノイズが多い
474
+ * 日本語:Bigram
475
+ * 例:ポスグレ→ポス|スグ|グレ|レ
476
+ * 漏れがない
477
+
478
+ = 形態素解析器ベース
479
+
480
+ * MeCab:OSS
481
+ * 新語対応には辞書メンテが必要
482
+ * 参考:mecab-ipadic-neologd
483
+ * JMAT:商用製品
484
+ * ジャストシステム社製
485
+ * ATOKでも使っている辞書を提供
486
+ * 新語にも強い\n
487
+ (('note:参考:「JMAT Groonga Tokenizer Talks」で検索'))
488
+
489
+ = amindexでのポイント
490
+
491
+ * (({amoptions()}))
492
+ * (({CREATE INDEX}))でのオプションを定義
493
+
494
+ # coderay sql
495
+ CREATE INDEX index ON memos
496
+ USING pgroonga (content)
497
+ WITH (normalizer = 'NormalizerMySQLUnicodeCI',
498
+ tokenizer = 'TokenMecab');
499
+
500
+ = 速さ以外の利点2
501
+
502
+ 見慣れた機能\n
503
+ (('note:B-tree・GINの代わりに使える'))
504
+
505
+ = タグ検索
506
+
507
+ # coderay sql
508
+ CREATE TABLE memos (
509
+ tags varchar(1023)[]
510
+ );
511
+ CREATE INDEX index ON memos
512
+ USING pgroonga (tags);
513
+ SELECT * FROM memos
514
+ WHERE tags %% 'タグ';
515
+
516
+ = 範囲検索
517
+
518
+ # coderay sql
519
+ CREATE TABLE users (age int);
520
+ CREATE INDEX index ON users
521
+ USING pgroonga (age);
522
+ SELECT * FROM users
523
+ WHERE age < 20;
524
+
525
+ = Index Only Scan
526
+
527
+ * 索引がデータも返す
528
+ * テーブルにアクセスしないので高速
529
+ * PGroonga・B-tree:サポート
530
+ * GIN:未サポート
531
+
532
+ = amindexでのポイント
533
+
534
+ * (({amcanreturn()}))
535
+ * (({true}))を返す
536
+ * (({amgettuple()}))
537
+ * (({scan->xs_want_itup}))なら\n
538
+ (({scan->xs_itup}))にデータを設定
539
+
540
+ = LIKE
541
+
542
+ # coderay sql
543
+ CREATE INDEX index ON memos
544
+ USING pgroonga (content);
545
+ SELECT * FROM memos
546
+ WHERE content LIKE '%...%';
547
+
548
+ (('tag:center'))
549
+ 索引を使って高速検索\n
550
+ アプリケーションの変更不要
551
+
552
+ = マルチカラムインデックス
553
+
554
+ # coderay sql
555
+ CREATE INDEX index ON memos
556
+ USING pgroonga (title, content);
557
+ SELECT * FROM memos
558
+ WHERE title @@ '...' AND
559
+ content @@ '...';
560
+
561
+ (('tag:center'))
562
+ (('note:titleでもcontentでもマッチ!'))\n
563
+ (('note:と書けないのでそんなにうれしくない'))
564
+
565
+ = 設計ミス
566
+
567
+ = (({text @@ text}))
568
+
569
+ (('tag:center'))
570
+ 組み込みの定義と競合\n
571
+ (('note:ts_vector @@ ts_queryにキャストされる'))
572
+
573
+ (('tag:margin-top * 2'))
574
+ 回避方法:
575
+
576
+ # coderay sql
577
+ ALTER DATABASE name
578
+ SET search_path = '$user',public,pgroonga,pg_catalog;
579
+
580
+ = (({jsonb @@ text}))
581
+
582
+ (('tag:center'))
583
+ 全文検索にすればよかった
584
+
585
+ # coderay sql
586
+ jsonb @@ 'string @ "キーワード"'
587
+ -- ↓
588
+ jsonb @@ 'キーワード'
589
+
590
+ (('tag:center'))
591
+ (('note:今の細かい検索条件を指定できる機能は別演算子にする'))
592
+
593
+ = 今後
594
+
595
+ = もっとGroongaを活かす
596
+
597
+ # RT
598
+ delimiter = [|]
599
+
600
+ PGroonga | pg_bigm | Groonga
601
+
602
+ 0.646s | 0.556s | 0.085s(!)
603
+
604
+ (('note:ヒット数635,792、検索語は2文字'))
605
+
606
+ (('tag:center'))
607
+ 生Groongaは1桁速い!\n
608
+ (('note:詳細:https://github.com/groonga/wikipedia-search/issues/3'))
609
+
610
+ = 同義語展開サポート
611
+
612
+ # coderay sql
613
+ body @@ pgroonga.expand_query('ネジ')
614
+ -- ↓
615
+ body @@ 'ネジ OR ねじ OR ボルト'
616
+
617
+ (('tag:center'))
618
+ (('note:Groongaでは使える'))
619
+
620
+ = ステミングサポート
621
+
622
+ found/finds\n
623
+ ↓\n
624
+ find\n
625
+ (('note:Groongaでは使える'))
626
+
627
+ = text @@ pgroonga.query
628
+
629
+ # coderay sql
630
+ body @@ 'ポスグレ'::pgroonga.query
631
+
632
+ (('tag:center'))
633
+ (('note:組み込みの(({text @@ text}))との競合回避'))
634
+
635
+ = 重みサポート
636
+
637
+ # coderay sql
638
+ -- タイトルのほうが本文より10倍重要
639
+ body @@ ('title * 10 || body', 'ポスグレ')
640
+
641
+ (('tag:center'))
642
+ (('note:Groongaでは使える'))
643
+
644
+ = まとめ
645
+
646
+ * PGroongaは速い
647
+ * PGroongaは便利
648
+ * PGroongaには設計ミスがある
649
+ * PGroongaはもっと便利になる
650
+
651
+ (('wait'))
652
+ (('tag:center'))
653
+ PGroongaを使おう!
654
+
655
+ = おしらせ
656
+
657
+ * Groonga Meatup 2015\n
658
+ (('note:https://groonga.doorkeeper.jp/events/31482'))
659
+ * PGroongaの話題もアリ
660
+ * 多少空きアリ(('note:(定員を多少増やせる)'))
661
+ * 11月29日(日)13:30開始