rabbit-slide-kou-jpmug-db-study-1 2018.1.30.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.
Binary file
@@ -0,0 +1,952 @@
1
+ = MariaDBとMroongaで作る\n全言語対応\n超高速全文検索システム
2
+
3
+ : author
4
+ 須藤功平
5
+ : institution
6
+ クリアコード
7
+ : content-source
8
+ 第一回 JPMUG DB勉強会
9
+ : date
10
+ 2018-01-30
11
+ : start-time
12
+ 2018-01-30T19:25:00+09:00
13
+ : end-time
14
+ 2018-01-30T20:10:00+09:00
15
+ : theme
16
+ .
17
+
18
+ = 全文検索システム\n対象
19
+
20
+ (('tag:center'))
21
+ (('tag:large'))
22
+ (('tag:margin-bottom * 2'))
23
+ 大量のテキスト
24
+
25
+ * 例:Wikiのデータ
26
+ * 例:オフィス文書のテキスト
27
+ * 例:商品説明・口コミ
28
+
29
+ = 全文検索システム\n目的
30
+
31
+ * 必要な情報を
32
+ * 必要なときに
33
+ * 活用
34
+
35
+ = 必要な情報を活用
36
+
37
+ * ×
38
+ * 探している情報が見つからない
39
+ * ○
40
+ * 探している情報が見つかる
41
+ * ◎
42
+ * 意識していなかったけど\n
43
+ ((*実は欲しかった*))情報も見つかる!
44
+
45
+ = 必要なときに活用
46
+
47
+ * ×
48
+ * なかなか見つからない
49
+ * ○
50
+ * すぐに見つかる
51
+ * ◎
52
+ * すでに見つかっていた
53
+ * 例:レコメンデーション
54
+
55
+ = 実装方法\n選択肢
56
+
57
+ * 全文検索サーバーを使う
58
+ * MariaDBでLIKEを使う
59
+
60
+ = 全文検索サーバー案\nメリット
61
+
62
+ * 必要な機能が揃っている
63
+ * +αの機能もある
64
+ * 速い
65
+
66
+ = 全文検索サーバー案\nデメリット
67
+
68
+ * 実装コスト大
69
+ * それぞれ独自の使い方だから
70
+ * マスターデータの同期はどうする?
71
+ * メンテナンスコスト大
72
+ * それぞれ独自の仕組みだから
73
+
74
+ = MariaDBでLIKE案\nメリット
75
+
76
+ * 実装コスト小
77
+ * 新しく覚えることが少ない
78
+ * データの一元管理
79
+ * メンテナンスコスト小
80
+ * 既存の運用ノウハウを使える
81
+ * データ少なら実用的な速度
82
+
83
+ = MariaDBでLIKE案\nデメリット
84
+
85
+ * 機能不足
86
+ * それっぽい順のソート不可
87
+ * 全文検索ではソート順が重要
88
+ * ユーザーは先頭n件しか見ない
89
+ * SQLの表現力不足
90
+ * nクエリーで実現すると性能に影響
91
+
92
+ = 実現方法\n第3の選択肢
93
+
94
+ * MariaDB経由(SQL)で\n
95
+ 全文検索エンジンを使う
96
+
97
+ = メリット
98
+
99
+ * 高速で豊富な機能
100
+ * それっぽい順のソート可
101
+ * 実装コスト小
102
+ * メンテナンスコスト小
103
+
104
+ = デメリット
105
+
106
+ * MariaDBに拡張機能が必要
107
+ * RDS・Azure databaseで使えない\n
108
+ (('note:(Azure database for MariaDBはまだリリース前)'))
109
+
110
+ = オススメの選択肢\n全文検索の知識ナシ
111
+
112
+ * まだ単純な機能で十分
113
+ * データ少:MariaDB単独でLIKE\n
114
+ (('note:(数十万件とか)'))
115
+ * データ中以上:\n
116
+ MariaDB経由で全文検索エンジン
117
+ * いまどきの全文検索機能が必要
118
+ * MariaDB経由で全文検索エンジン
119
+
120
+ = オススメの選択肢\n全文検索の知識アリ
121
+
122
+ * カリカリにチューニングしたい
123
+ * MariaDBと全文検索サーバーを併用
124
+ * それ以外
125
+ * MariaDB経由で全文検索エンジン
126
+
127
+ = 説明する選択肢
128
+
129
+ MariaDB経由で\n
130
+ 全文検索\n
131
+ エンジン
132
+
133
+ = 全文検索エンジン\nGroonga(ぐるんが)
134
+
135
+ * 組込可能な全文検索エンジン
136
+ * MariaDB・MySQLに組込→Mroonga
137
+ * PostgreSQLに組込→PGroonga
138
+ * 全文検索サーバーとして\n
139
+ 単独でも使用可能
140
+ * MariaDBと全文検索サーバーを併用\n
141
+ もできる
142
+
143
+ = Groongaの得意なこと
144
+
145
+ * データの追加・更新
146
+ * 新鮮な情報をすぐに検索可能に!
147
+ * 更新中も検索性能を落とさない!
148
+ * 日本語
149
+ * 開発者が日本人
150
+ * 便利機能が組み込み
151
+
152
+ = GroongaとUnicode
153
+
154
+ * NFKCベースの正規化機能を組込
155
+ * Unicode 5.1ベースで古い
156
+ * 2008年の仕様
157
+ * Unicode 10.0(最新)対応中\n
158
+ (('note:正規化方式を変えるとインデックスの互換性がなくなる(=要インデックス再構築)のでデフォルトは変えない'))
159
+
160
+ = Mroonga(むるんが)
161
+
162
+ * MariaDBのストレージエンジン
163
+ * InnoDB・MyISAMなどと同じレイヤー
164
+ * MariaDB 10.0.15から標準バンドル
165
+ * 使用方法
166
+ * (({CREATE TABLE (...) ENGINE=Mroonga}))
167
+
168
+ = 照合順序:COLLATION
169
+
170
+ * 文字の並び順の規則
171
+ * 文字が同一かどうかの判定にも利用
172
+ * 適切な日本語規則なし
173
+ * いわゆる🍣=🍺問題
174
+
175
+ (('note:MySQL 8では適切な日本語規則が追加される'))\n
176
+ (('note:utf8mb4_ja_0900_as_csなど'))
177
+
178
+ = Mroongaの照合順序
179
+
180
+ * MariaDB互換のもの
181
+ * (({utf8mb4_ja_0900_*}))互換は対応予定
182
+ * MariaDB互換を微調整したもの
183
+ * 日本語でもいい感じ
184
+ * Groonga提供のもの
185
+ * NFKCベースのもの
186
+ * 日本語でもいい感じ
187
+
188
+ = Mroongaで照合順序
189
+
190
+ * MariaDB互換がよい!
191
+ * 互換正規化処理を使用:デフォルト
192
+ * MariaDB互換は気にしないから\n
193
+ いい感じに!
194
+ * Groonga提供のものを使用
195
+
196
+ = 全文検索性能\n計測データ
197
+
198
+ * 対象:Wikipedia日本語版
199
+ * レコード数:約185万件
200
+ * データサイズ:約7GB
201
+ * メモリー4GB・SSD250GB(('note:(ConoHa)'))
202
+
203
+ = 検索性能1
204
+
205
+ (('tag:center'))
206
+ キーワード:テレビアニメ\n
207
+ (('note:(ヒット数:約2万3千件)'))
208
+
209
+ # RT
210
+ delimiter = [|]
211
+
212
+ InnoDB ngram | 3m2s
213
+ InnoDB MeCab | 6m20s
214
+ Mroonga:((*1*)) | 0.11s
215
+
216
+ = 検索性能2
217
+
218
+ (('tag:center'))
219
+ キーワード:データベース\n
220
+ (('note:(ヒット数:約1万7千件)'))
221
+
222
+ # RT
223
+ delimiter = [|]
224
+
225
+ InnoDB ngram | 36s
226
+ InnoDB MeCab:((*1*)) | 0.03s
227
+ Mroonga:((*2*)) | 0.09s
228
+
229
+ = 検索性能3
230
+
231
+ (('tag:center'))
232
+ キーワード:PostgreSQL OR MySQL\n
233
+ (('note:(ヒット数:約400件)'))
234
+
235
+ # RT
236
+ delimiter = [|]
237
+
238
+ InnoDB ngram | N/A(Error)
239
+ InnoDB MeCab:((*1*)) | 0.005s
240
+ Mroonga:((*2*)) | 0.028s
241
+
242
+ = 検索性能4
243
+
244
+ (('tag:center'))
245
+ キーワード:日本\n
246
+ (('note:(ヒット数:約63万件)'))
247
+
248
+ # RT
249
+ delimiter = [|]
250
+
251
+ InnoDB ngram | 1.3s
252
+ InnoDB MeCab | 1.3s
253
+ Mroonga:((*1*)) | 0.21s
254
+
255
+ = 全文検索性能まとめ
256
+
257
+ * Mroonga:安定して速い
258
+ * ((*SQLで使えて機能豊富で速い!*))
259
+ * InnoDB FTS MeCab
260
+ * ハマれば速い
261
+ * InnoDB FTS ngram
262
+ * 安定して遅い
263
+
264
+ = 普通の検索も速い
265
+
266
+ * カラムストアを活かした最適化
267
+ * ポイント1:余計なI/Oを減らす
268
+ * ポイント2:I/Oを局所化
269
+
270
+ = カラムストア
271
+
272
+ # image
273
+ # src = images/column-store.svg
274
+ # relative_width = 100
275
+
276
+ = 必要なカラムのみアクセス
277
+
278
+ # coderay sql
279
+ -- aのみにアクセス
280
+ SELECT a
281
+ FROM table
282
+ -- cのみにアクセス
283
+ WHERE c = XXX;
284
+ -- bにはアクセスしない
285
+
286
+ = 減ったI/O
287
+
288
+ # image
289
+ # src = images/not-access-to-needless-columns.svg
290
+ # relative_width = 100
291
+
292
+ = 行カウント
293
+
294
+ # coderay sql
295
+ -- カラムの値は必要ない
296
+ SELECT COUNT(*)
297
+ FROM table
298
+ -- cの全文検索インデックスにだけアクセス
299
+ WHERE MATCH(c)
300
+ AGAINST('+keyword' IN BOOLEAN MODE);
301
+ -- a, b, cはアクセスしない
302
+
303
+ = 減ったI/O
304
+
305
+ # image
306
+ # src = images/count-star.svg
307
+ # relative_width = 100
308
+
309
+ = (({ORDER BY LIMIT}))
310
+
311
+ # coderay sql
312
+ SELECT a
313
+ FROM table
314
+ WHERE MATCH(c)
315
+ AGAINST('+keyword' IN BOOLEAN MODE)
316
+ -- MariaDBではなくMroongaがORDER BY LIMITを処理
317
+ -- →Mroongaは10レコードだけMariaDBに返す
318
+ -- マッチしたレコードすべては返さない
319
+ ORDER BY a LIMIT 10;
320
+
321
+ = (({ORDER BY LIMIT}))の最適化
322
+
323
+ * Mroongaが検索
324
+ * カラム毎の処理でI/Oを局所化\n
325
+ (('note:(索引非使用時)'))
326
+ * Mroongaがソート
327
+ * カラム毎の処理でI/Oを局所化
328
+ * Mroongaが(({OFFSET}))/(({LIMIT}))を処理
329
+
330
+ = カラム毎の処理は速い
331
+
332
+ # image
333
+ # src = images/per-column-processing.svg
334
+ # relative_width = 100
335
+
336
+ = condition push downの最適化
337
+
338
+ * 従来はMariaDBが処理していた検索条件をストレージエンジンが処理する仕組み
339
+ * ストレージエンジンでの処理の方が高速なら全体として高速になる
340
+ * Mroonga 7.10から実験的に対応
341
+ * デフォルトオフ
342
+
343
+ = condition push downの効果
344
+
345
+ * 全文検索インデックスのみ
346
+ * 等価条件:シーケンシャルスキャン
347
+ * 全文検索:インデックススキャン
348
+ * データ
349
+ * シカゴの犯罪データ(('note:(651万レコード)'))
350
+
351
+ (('tag:xx-small'))
352
+ 詳細:((<"https://github.com/kou/rabbit-slide-kou-jpmug-db-study-1/blob/master/memo.md"|URL:https://github.com/kou/rabbit-slide-kou-jpmug-db-study-1/blob/master/memo.md>))
353
+
354
+ = 等価条件:数値1つ
355
+
356
+ (('tag:center'))
357
+ 26万件ヒットするケース
358
+
359
+ # RT
360
+ delimiter = [|]
361
+
362
+ InnoDB | 1.3s
363
+ Mroonga\n(デフォルト) | 1.3s
364
+ Mroonga\n(最適化ON) | 0.4s
365
+
366
+ = 等価条件:数値1つ+真偽値2つ
367
+
368
+ (('tag:center'))
369
+ 7000件ヒットするケース
370
+
371
+ # RT
372
+ delimiter = [|]
373
+
374
+ InnoDB | 1.6s
375
+ Mroonga\n(デフォルト) | 2.3s
376
+ Mroonga\n(最適化ON) | 0.4s
377
+
378
+ = 全文検索+等価条件
379
+
380
+ (('tag:center'))
381
+ 4000件ヒットするケース
382
+
383
+ # RT
384
+ delimiter = [|]
385
+
386
+ InnoDB | 18s
387
+ Mroonga\n(デフォルト) | 0.4s
388
+ Mroonga\n(最適化ON) | 0.4s
389
+
390
+ (('note:このパターンはデフォルトで最適化が効く'))
391
+
392
+ = Mroongaの検索性能まとめ
393
+
394
+ * 最適化が効くと桁違いに速い
395
+ * 全文検索のときはデフォルトで効く
396
+ * 7.10からさらなる最適化が!\n
397
+ (('note:まだ実験的扱いなのでデフォルトオフ'))
398
+ * OLAP用途にも使える
399
+ * MariaDB ColumnStoreを補完する\n
400
+ 立ち位置も可
401
+
402
+ (('tag:xx-small'))
403
+ 参考:((<"http://mroonga.org/ja/docs/reference/server_variables.html#mroonga-condition-push-down-type"|URL:http://mroonga.org/ja/docs/reference/server_variables.html#mroonga-condition-push-down-type>))
404
+
405
+ = 全文検索システムの実装
406
+
407
+ * 全文検索
408
+ * キーワードハイライト
409
+ * 周辺テキスト表示
410
+ * オートコンプリート
411
+ * 同義語展開
412
+ * 関連文書の表示
413
+
414
+ = 全文検索
415
+
416
+ # image
417
+ # src = images/php-document-search-search.png
418
+ # relative_height = 100
419
+
420
+ = テーブル定義
421
+
422
+ # coderay sql
423
+
424
+ CREATE TABLE entries (
425
+ title text,
426
+ content text,
427
+ -- 全文検索用インデックス
428
+ -- よくわからないならデフォルトのまま使うこと!
429
+ FULLTEXT INDEX (title, content)
430
+ ) ENGINE=Mroonga
431
+ DEFAULT CHARSET=utf8mb4;
432
+
433
+ = データ挿入
434
+
435
+ # coderay sql
436
+
437
+ -- 普通に挿入するだけでよい
438
+ INSERT INTO entries
439
+ VALUES ('タイトル',
440
+ '高速に全文検索したいですね!');
441
+
442
+ = 全文検索
443
+
444
+ # coderay sql
445
+
446
+ SELECT title FROM entries
447
+ WHERE -- MATCH AGAINSTで全文検索
448
+ MATCH (title, content)
449
+ -- デフォルトORがMariaDBの仕様
450
+ -- 「検索」または「高速」を含むとマッチ
451
+ AGAINST ('検索 高速'
452
+ IN BOOLEAN MODE);
453
+
454
+ = AND全文検索
455
+
456
+ # coderay sql
457
+
458
+ MATCH (title, content)
459
+ -- 各キーワードの前に「+」をつけるとAND
460
+ -- 「検索」かつ「高速」を含むとマッチ
461
+ AGAINST ('+検索 +高速'
462
+ IN BOOLEAN MODE);
463
+
464
+ = 使いやすいAND全文検索
465
+
466
+ # coderay sql
467
+
468
+ MATCH (title, content)
469
+ -- 最初に「*D+」をつけるとデフォルトAND
470
+ -- Mroonga独自機能
471
+ -- 「検索」かつ「高速」を含むとマッチ
472
+ AGAINST ('*D+ 検索 高速'
473
+ IN BOOLEAN MODE);
474
+
475
+ = それっぽい順のソート
476
+
477
+ # coderay sql
478
+
479
+ SELECT
480
+ title,
481
+ -- ここのMATCH AGAINSTはスコアーを返す
482
+ MATCH (title, content)
483
+ AGAINST ('*D+ 検索 高速'
484
+ IN BOOLEAN MODE) AS score
485
+ FROM entries
486
+ WHERE -- ...
487
+ -- それっぽさでソート
488
+ ORDER BY score DESC LIMIT 10;
489
+
490
+ = ハイライト
491
+
492
+ # image
493
+ # src = images/php-document-search-search.png
494
+ # relative_height = 100
495
+
496
+ = ハイライト
497
+
498
+ # coderay sql
499
+
500
+ SELECT mroonga_highlight_html(
501
+ title, '*D+ 検索 高速' AS query)
502
+ -- クエリーからハイライト対象のキーワードを抽出
503
+ FROM entries
504
+ WHERE
505
+ MATCH (title, content)
506
+ AGAINST ('*D+ 検索 高速' IN BOOLEAN MODE);
507
+
508
+ = ハイライト結果例
509
+
510
+ # coderay html
511
+
512
+ <Groonga>で高速全文検索!
513
+
514
+ &lt;Groonga&gt;で ← タグをエスケープ
515
+ <span class="keyword">高速</span>
516
+ 全文 ↑↓キーワードはclass付け
517
+ <span class="keyword">検索</span>!
518
+
519
+ = 周辺テキスト
520
+
521
+ # image
522
+ # src = images/php-document-search-search.png
523
+ # relative_height = 100
524
+
525
+ = 周辺テキスト
526
+
527
+ # coderay sql
528
+
529
+ SELECT mroonga_snippet_html(
530
+ content, '*D+ 検索 高速' AS query)
531
+ -- クエリーから対象のキーワードを抽出
532
+ FROM entries
533
+ WHERE
534
+ MATCH (title, content)
535
+ AGAINST ('*D+ 検索 高速' IN BOOLEAN MODE);
536
+
537
+ = 周辺テキスト結果例
538
+
539
+ # coderay html
540
+
541
+ ...<Groonga>で高速全文検索!...
542
+
543
+ <div class="snippet"> ←1つ目
544
+ ga&gt;で ←タグをエスケープ
545
+ <span class="keyword">高速</span>
546
+ 全文 ↑↓キーワードはclass付け
547
+ <span class="keyword">検索/span>!
548
+ </div>
549
+ <div class="snippet">...</div> ←2つ目
550
+
551
+ = オートコンプリート
552
+
553
+ # image
554
+ # src = images/php-document-search.png
555
+ # relative_height = 100
556
+
557
+ = オートコンプリート:必要なもの
558
+
559
+ * マスターテーブル
560
+ * 候補(例:牛乳)
561
+ * 候補のヨミ(カタカナ・複数可)
562
+ * 例1:ギュウニュウ
563
+ * 例2:ミルク
564
+
565
+ = オートコンプリート:実装方法
566
+
567
+ * 以下の検索のOR
568
+ * ヨミでの前方一致検索
569
+ * 候補を緩い全文検索
570
+ * 候補でソートして提示
571
+
572
+ = オートコンプリート:テーブル定義
573
+
574
+ # coderay sql
575
+
576
+ CREATE TABLE terms (
577
+ term varchar(256), -- 補完候補
578
+ reading varchar(256), -- ヨミガナ
579
+ PRIMARY KEY (term, reading),
580
+ FULLTEXT INDEX (term) -- 候補全文検索用
581
+ -- 緩い全文検索用トークナイザー
582
+ COMMENT 'tokenizer "TokenBigramSplitSymbolAlpha"',
583
+ FULLTEXT INDEX (reading) -- ヨミガナ前方一致用
584
+ COMMENT 'normalizer "NormalizerAuto",
585
+ tokenizer "off"' -- トークナイザー不要
586
+ ) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
587
+
588
+ = オートコンプリート:データ例
589
+
590
+ # coderay sql
591
+
592
+ INSERT INTO terms VALUES (
593
+ '牛乳', -- 補完候補
594
+ 'ギュウニュウ' --ヨミガナはカタカナで指定
595
+ );
596
+ INSERT INTO terms VALUES (
597
+ '牛乳',
598
+ 'ミルク' -- 「ミルク」でも補完できるように
599
+ );
600
+
601
+ = オートコンプリート\nデータ管理のポイント
602
+
603
+ * 普通のテーブルなので管理が楽
604
+ * 追加・削除・更新が楽
605
+ * ダンプ・リストアもいつも通り
606
+ * レプリケーションもいつも通り
607
+
608
+ = オートコンプリート\n検索方法
609
+
610
+ # coderay sql
611
+
612
+ SELECT DISTINCT(term) FROM terms
613
+ WHERE MATCH (reading) -- ヨミガナ前方一致検索
614
+ AGAINST (CONCAT('*SS prefix_rk_search(reading, ',
615
+ mroonga_escape(${入力} AS script),
616
+ ')') IN BOOLEAN MODE) OR
617
+ MATCH (term) -- 候補を緩く全文検索
618
+ AGAINST (CONCAT('*D+ ', mroonga_escape(${入力})))
619
+ IN BOOLEAN MODE)
620
+ ORDER BY term LIMIT 10; -- ソート
621
+
622
+ = オートコンプリート\n検索例:漢字1
623
+
624
+ # coderay sql
625
+
626
+ -- ユーザーが「牛」を入力した場合
627
+ SELECT DISTINCT(term) FROM terms
628
+ WHERE MATCH (reading) -- ヨミガナ前方一致検索
629
+ AGAINST (CONCAT('*SS prefix_rk_search(reading, ',
630
+ mroonga_escape('牛' AS script),
631
+ ')') IN BOOLEAN MODE) OR
632
+ MATCH (term) -- 候補を緩く全文検索(ヒット)
633
+ AGAINST (CONCAT('*D+ ', mroonga_escape('牛')))
634
+ IN BOOLEAN MODE)
635
+ ORDER BY term LIMIT 10; -- ソート
636
+
637
+ = オートコンプリート\n検索例:漢字2
638
+
639
+ # coderay sql
640
+
641
+ -- ユーザーが「乳」を入力した場合
642
+ SELECT DISTINCT(term) FROM terms
643
+ WHERE MATCH (reading) -- ヨミガナ前方一致検索
644
+ AGAINST (CONCAT('*SS prefix_rk_search(reading, ',
645
+ mroonga_escape('乳' AS script),
646
+ ')') IN BOOLEAN MODE) OR
647
+ MATCH (term) -- 候補を緩く全文検索(ヒット)
648
+ AGAINST (CONCAT('*D+ ', mroonga_escape('乳')))
649
+ IN BOOLEAN MODE)
650
+ ORDER BY term LIMIT 10; -- ソート
651
+
652
+ = オートコンプリート\n検索例:カタカナ
653
+
654
+ # coderay sql
655
+
656
+ -- ユーザーが「ギュウ」を入力した場合
657
+ SELECT DISTINCT(term) FROM terms
658
+ WHERE MATCH (reading) -- ヨミガナ前方一致検索(ヒット)
659
+ AGAINST (CONCAT('*SS prefix_rk_search(reading, ',
660
+ mroonga_escape('ギュウ' AS script),
661
+ ')') IN BOOLEAN MODE) OR
662
+ MATCH (term) -- 候補を緩く全文検索
663
+ AGAINST (CONCAT('*D+ ', mroonga_escape('ギュウ')))
664
+ IN BOOLEAN MODE)
665
+ ORDER BY term LIMIT 10; -- ソート
666
+
667
+ = オートコンプリート\n検索例:ひらがな
668
+
669
+ # coderay sql
670
+
671
+ -- ユーザーが「ぎゅう」を入力した場合
672
+ SELECT DISTINCT(term) FROM terms
673
+ WHERE MATCH (reading) -- ヨミガナ前方一致検索(ヒット)
674
+ AGAINST (CONCAT('*SS prefix_rk_search(reading, ',
675
+ mroonga_escape('ぎゅう' AS script),
676
+ ')') IN BOOLEAN MODE) OR
677
+ MATCH (term) -- 候補を緩く全文検索
678
+ AGAINST (CONCAT('*D+ ', mroonga_escape('ぎゅう')))
679
+ IN BOOLEAN MODE)
680
+ ORDER BY term LIMIT 10; -- ソート
681
+
682
+ = オートコンプリート\n検索例:ローマ字
683
+
684
+ # coderay sql
685
+
686
+ -- ユーザーが「gyu」を入力した場合
687
+ SELECT DISTINCT(term) FROM terms
688
+ WHERE MATCH (reading) -- ヨミガナ前方一致検索(ヒット)
689
+ AGAINST (CONCAT('*SS prefix_rk_search(reading, ',
690
+ mroonga_escape('gyu' AS script),
691
+ ')') IN BOOLEAN MODE) OR
692
+ MATCH (term) -- 候補を緩く全文検索
693
+ AGAINST (CONCAT('*D+ ', mroonga_escape('gyu')))
694
+ IN BOOLEAN MODE)
695
+ ORDER BY term LIMIT 10; -- ソート
696
+
697
+ = 同義語展開
698
+
699
+ * 同義語
700
+ * 同じ意味だが表記が異なる語
701
+ * 例:「刺身」と「お造り」
702
+ * どの表記でもヒットして欲しい
703
+ * 同義語展開→同義語すべてでOR検索
704
+
705
+ = 同義語展開\n実装方法
706
+
707
+ * 同義語管理テーブルを作成
708
+ * クエリー内の同義語を展開
709
+ * 展開後のクエリーで検索
710
+
711
+ = 同義語展開:Mroonga\nテーブル定義
712
+
713
+ # coderay sql
714
+ CREATE TABLE synonyms (
715
+ term varchar(255), -- 展開対象の語
716
+ synonym varchar(255), -- 同義語
717
+ INDEX (term) -- 高速化と精度向上
718
+ COMMENT 'normalizer "NormalizerAuto"'
719
+ ) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
720
+
721
+ = 同義語展開\nデータ例
722
+
723
+ # coderay sql
724
+ INSERT INTO synonyms
725
+ -- 「刺身」を「刺身 OR お造り」に展開
726
+ VALUES ('刺身', '刺身'),
727
+ ('刺身', 'お造り'),
728
+ -- 「お造り」を「お造り OR 刺身」に展開
729
+ ('お造り', 'お造り'),
730
+ ('お造り', '刺身');
731
+
732
+ = 同義語展開\nデータ管理のポイント
733
+
734
+ * 普通のテーブルなので管理が楽
735
+ * 追加・削除・更新が楽
736
+ * ダンプ・リストアもいつも通り
737
+ * レプリケーションもいつも通り
738
+
739
+ = 同義語展開:Mroonga\n確認方法
740
+
741
+ # coderay sql
742
+
743
+ SELECT mroonga_query_expand(
744
+ 'synonyms', -- テーブル名
745
+ 'term', -- 展開対象のカラム名
746
+ 'synonym', -- 対応する同義語のカラム名
747
+ '居酒屋 刺身' -- クエリー
748
+ );
749
+ -- '居酒屋 ((刺身) OR (お造り))'
750
+
751
+ = 同義語展開:Mroonga\n検索方法
752
+
753
+ # coderay sql
754
+ SELECT title FROM entries
755
+ WHERE
756
+ MATCH (title)
757
+ -- '*D+ 居酒屋 OR ((刺身) OR (お造り))'になる
758
+ AGAINST (mroonga_query_expand('synonyms',
759
+ 'term',
760
+ 'synonym',
761
+ '*D+ 居酒屋 刺身')
762
+ IN BOOLEAN MODE);
763
+
764
+ = 類似文書検索
765
+
766
+ * 検索クエリーは文書そのもの
767
+ * キーワードではない
768
+ * 関連エントリーの提示に使える
769
+ * メタデータがあるなら組み合わせる\n
770
+ →精度向上
771
+ * メタデータ:タグ・行動履歴など
772
+
773
+ = 類似文書検索:Mroonga\nインデックス定義
774
+
775
+ # coderay sql
776
+
777
+ CREATE TABLE entries (
778
+ -- ...
779
+ FULLTEXT INDEX (content)
780
+ -- TokenMecabを使わないと精度がでない
781
+ -- 必要なときだけカスタマイズ!
782
+ COMMENT 'tokenizer "TokenMecab"'
783
+ ) -- ...
784
+
785
+ = 類似文書検索:Mroonga\n検索方法
786
+
787
+ # coderay sql
788
+
789
+ SELECT title
790
+ FROM entries
791
+ WHERE
792
+ MATCH (content)
793
+ -- ↓ 既存文書の内容をそのまま指定
794
+ AGAINST ('...Groongaで高速全文検索!...'
795
+ IN NATURAL LANGUAGE MODE);
796
+
797
+ = 類似文書検索:Mroonga\n結果例
798
+
799
+ クエリー:
800
+ ...Groongaで高速全文検索!...
801
+
802
+ ヒット例:
803
+ ...Mroongaで高速全文検索!...
804
+
805
+ = 全文検索システムの実装\nまとめ
806
+
807
+ * 全文検索
808
+ * キーワードハイライト
809
+ * 周辺テキスト表示
810
+ * オートコンプリート
811
+ * 同義語展開
812
+ * 関連文書の表示
813
+
814
+ = 全文検索システムの実装\n次の一歩
815
+
816
+ * 構造化データ対応
817
+ * オフィス文書・HTMLなど
818
+ * 対応に必要な処理
819
+ * テキスト抽出
820
+ * メタデータ抽出(('note:(例:タイトル・更新日時)'))
821
+ * スクリーンショット作成(('note:(なおよい)'))
822
+
823
+ = 抽出ツール
824
+
825
+ * Apache Tika
826
+ * Apache Luceneのサブプロジェクト
827
+ * 対応フォーマット数が多い
828
+ * ChupaText
829
+ * Groongaのサブプロジェクト
830
+ * スクリーンショット作成対応
831
+
832
+ = ChupaText
833
+
834
+ * 対応フォーマット
835
+ * Word/Excel/PowerPoint
836
+ * ODT/ODS/ODP(('note:(OpenDocument)'))
837
+ * PDF/HTML/XML/CSV/...
838
+ * インターフェイス
839
+ * HTTPとコマンドライン
840
+
841
+ = ChupaText:インストール
842
+
843
+ * DockerかVagrantを使うのが楽
844
+ * (('tag:xx-small'))
845
+ https://github.com/ranguba/chupa-text-docker
846
+ * (('tag:xx-small'))
847
+ https://github.com/ranguba/chupa-text-vagrant
848
+
849
+ = ChupaText:Docker
850
+
851
+ # coderay console
852
+ % GITHUB=https://github.com
853
+ % git clone \
854
+ ${GITHUB}/ranguba/chupa-text-docker.git
855
+ % cd chupa-text-docker
856
+ % docker-compose up --build
857
+
858
+ = ChupaText:使い方
859
+
860
+ # coderay console
861
+ % curl \
862
+ --form data=@XXX.pdf \
863
+ http://localhost:20080/extraction.json
864
+
865
+ = ChupaText:結果例
866
+
867
+ # coderay json
868
+
869
+ {
870
+ "mime-type": "application/pdf", # 元データのMIMEタイプ
871
+ "size": 147159, # メタデータ
872
+ ...,
873
+ "texts": [ # 抽出されたテキスト(N個)
874
+ {
875
+ "mime-type": "text/plain", # 抽出後のMIMEタイプ
876
+ ...,
877
+ "creator": "Adobe Illustrator CS3", # メタデータ
878
+ "body": "This is sample PDF. ...", # 抽出したテキスト
879
+ "screenshot": {
880
+ "mime-type": "image/png", # スクリーンショットのMIMEタイプ
881
+ "data": "iVBORw...", # Base64にした画像データ
882
+ "encoding": "base64" # Base64であることを明記
883
+ }
884
+ }
885
+ ]
886
+ }
887
+
888
+ = ChupaText:Web UI
889
+
890
+ # image
891
+ # src = images/chupa-text-web-ui-form.png
892
+ # relative_height = 100
893
+
894
+ = ChupaText:Web UI抽出例
895
+
896
+ # image
897
+ # src = images/chupa-text-web-ui-extract-metadata.png
898
+ # relative_height = 100
899
+
900
+ = ChupaText:Web UI抽出例
901
+
902
+ # image
903
+ # src = images/chupa-text-web-ui-extract-text-and-screenshot.png
904
+ # relative_height = 100
905
+
906
+ = ChupaText:Vagrant
907
+
908
+ # coderay console
909
+ % GITHUB=https://github.com
910
+ % git clone \
911
+ ${GITHUB}/ranguba/chupa-text-vagrant.git
912
+ % cd chupa-text-vagrant
913
+ % vagrant up
914
+
915
+ (('tag:center'))
916
+ 使い方はDocker版と同じ
917
+
918
+ = ChupaText:活用例
919
+
920
+ * 抽出したテキスト
921
+ * Mroongaへ挿入
922
+ * 抽出したメタデータ
923
+ * Mroongaへ挿入
924
+ * 絞り込みに活用
925
+ * 作成したスクリーンショット
926
+ * 検索結果表示時に掲載
927
+
928
+ = まとめ
929
+
930
+ * MariaDBの全文検索まわり
931
+ * 全文検索システム実装例を紹介
932
+ * 構造化データの対応方法を紹介
933
+ * ChupaText
934
+
935
+ = 扱わなかった話題
936
+
937
+ * 運用について
938
+ * 障害対策・レプリケーション
939
+ * チューニング
940
+ * Groongaの機能を直接使う方法
941
+
942
+ = サポートサービス紹介
943
+
944
+ * 導入支援(('note:(設計支援・性能検証・移行支援・…)'))
945
+ * 開発支援\n
946
+ (('note:(サンプルコード提供・問い合わせ対応・…)'))
947
+ * 運用支援(('note:(障害対応・チューニング支援・…)'))
948
+
949
+ 問い合わせ先:
950
+
951
+ (('tag:x-small'))
952
+ ((<"https://www.clear-code.com/contact/?type=groonga"|URL:https://www.clear-code.com/contact/?type=groonga>))