rabbit-slide-kou-osc-2014-tokyo-fall 2014.10.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,772 @@
1
+ = いろいろ考えると\n日本語の全文検索も\nMySQLがいいね!
2
+
3
+ : author
4
+ 須藤功平
5
+ : institution
6
+ 日本MySQLユーザ会
7
+ : content-source
8
+ OSC2014 Tokyo/Fall
9
+ : date
10
+ 2014/10/18
11
+ : allotted-time
12
+ 45m
13
+ : theme
14
+ .
15
+
16
+ = 目標
17
+
18
+ 日本語対応の\n
19
+ 全文検索機能を\n
20
+ (('note:(そこそこ仕組みをわかった上で)'))\n
21
+ 実装できる
22
+
23
+ = 前提
24
+
25
+ * MySQLを使っている
26
+ * まあまあかそこそこのデータ量
27
+ * ビッグデータ云々じゃない\n
28
+ (('note:(そういう人はHadoopの枠に行っているよね?)'))
29
+ * 日本語テキストを検索したい
30
+ * でも、全文検索をよく知らない
31
+
32
+ = 全文検索について
33
+
34
+ 全文検索とは…
35
+
36
+ = とりあえず動かそう
37
+
38
+ * データベース作成
39
+ * テーブル作成
40
+ * データ投入
41
+ * 全文検索!
42
+
43
+ = データベース作成
44
+
45
+ # coderay sql
46
+ CREATE DATABASE full_text_search;
47
+ USE full_text_search;
48
+
49
+ = テーブル作成
50
+
51
+ # coderay sql
52
+ CREATE TABLE memos (
53
+ content TEXT
54
+ ) DEFAULT CHARSET=utf8mb4;
55
+
56
+ = データ投入
57
+
58
+ # coderay sql
59
+ INSERT INTO memos
60
+ VALUES ("Hello world!"),
61
+ ("Good-bye world!"),
62
+ ("Hello MySQL!");
63
+
64
+ = 全文検索!
65
+
66
+ # coderay sql
67
+ SELECT *
68
+ FROM memos
69
+ WHERE content LIKE "%Hello%";
70
+ -- +--------------+
71
+ -- | content |
72
+ -- +--------------+
73
+ -- | Hello world! |
74
+ -- | Hello MySQL! |
75
+ -- +--------------+
76
+
77
+ = 全文検索! - もっと
78
+
79
+ * AND
80
+ * OR
81
+ * 大文字小文字無視
82
+ * 日本語
83
+
84
+ = 全文検索! - AND
85
+
86
+ # coderay sql
87
+ SELECT *
88
+ FROM memos
89
+ WHERE content LIKE "%Hello%" AND
90
+ content LIKE "%world%";
91
+ -- +--------------+
92
+ -- | content |
93
+ -- +--------------+
94
+ -- | Hello world! |
95
+ -- +--------------+
96
+
97
+ = 全文検索! - OR
98
+
99
+ # coderay sql
100
+ SELECT *
101
+ FROM memos
102
+ WHERE content LIKE "%Good%" OR
103
+ content LIKE "%MySQL%";
104
+ -- +-----------------+
105
+ -- | content |
106
+ -- +-----------------+
107
+ -- | Good-bye world! |
108
+ -- | Hello MySQL! |
109
+ -- +-----------------+
110
+
111
+ = 大文字小文字無視
112
+
113
+ # coderay sql
114
+ SELECT *
115
+ FROM memos
116
+ WHERE content LIKE "%mysql%";
117
+ -- +--------------+
118
+ -- | content |
119
+ -- +--------------+
120
+ -- | Hello MySQL! |
121
+ -- +--------------+
122
+
123
+ = 大文字小文字無視 - 理由
124
+
125
+ # coderay sql
126
+ SHOW TABLE STATUS LIKE "memos"\G
127
+ -- ...
128
+ -- Collation: utf8mb4_general_ci
129
+ -- ...
130
+
131
+ = Collation
132
+
133
+ * 照合順序(('note:(って言われてわかる?)'))
134
+ * 文字の比較ルール
135
+ * 「a」と「b」はどっちが大きい?
136
+ * 「a」と「A」は等しい?
137
+ * utf8mb4_general_ci
138
+ * 同じようなアルファベットは同一視\n
139
+ (('note:(直感的だけど雑な説明)'))
140
+
141
+ = 日本語 - データ投入
142
+
143
+ # coderay sql
144
+ INSERT INTO memos
145
+ VALUES ("こんにちは"),
146
+ ("こんばんは");
147
+
148
+ = 日本語 - 全文検索!
149
+
150
+ # coderay sql
151
+ SELECT *
152
+ FROM memos
153
+ WHERE content LIKE "%こんにち%";
154
+ -- +-----------------+
155
+ -- | content |
156
+ -- +-----------------+
157
+ -- | こんにちは |
158
+ -- +-----------------+
159
+
160
+ = 全文検索の実装方法まとめ
161
+
162
+ * (({DEFAULT CHARSET=utf8mb4}))
163
+ * (({INSERT}))
164
+ * (({LIKE "%キーワード%"}))
165
+ * ANDもORも日本語も可
166
+ * 大文字小文字無視も可
167
+
168
+ = 日本語をもっと!
169
+
170
+ * (('note:いわゆる'))全角アルファベット対応
171
+
172
+ = 全角アルファベット
173
+
174
+ # coderay sql
175
+ SELECT *
176
+ FROM memos
177
+ WHERE content LIKE "%Hello%";
178
+ -- +-----------------+
179
+ -- | content |
180
+ -- +-----------------+
181
+ -- +-----------------+
182
+
183
+ = Collation変更
184
+
185
+ # coderay sql
186
+ ALTER TABLE memos
187
+ MODIFY COLUMN
188
+ content
189
+ TEXT
190
+ COLLATE utf8mb4_unicode_ci;
191
+
192
+ = utf8mb4_unicode_ci
193
+
194
+ * Unicode的に同じ文字を同一視\n
195
+ (('note:(直感的だけど雑な説明)'))\n
196
+ * 例:全角文字半角文字を同一視\n
197
+ (('note:参考:MySQL 5.5 の unicode collation で同一視される文字'))\n
198
+ (('note:http://tmtms.hatenablog.com/entry/20110416/mysql_unicode_collation'))
199
+ * utf8mb4_general_ciより遅い
200
+
201
+ = 全角アルファベット
202
+
203
+ # coderay sql
204
+ SELECT *
205
+ FROM memos
206
+ WHERE content LIKE "%Hello%";
207
+ -- +--------------+
208
+ -- | content |
209
+ -- +--------------+
210
+ -- | Hello world! |
211
+ -- | Hello MySQL! |
212
+ -- +--------------+
213
+
214
+ = 採用を検討
215
+
216
+ * 機能は十分?
217
+ * やりたいことと相談
218
+ * 性能は十分?
219
+ * データ量・リソースと相談
220
+ * 実データが望ましい!!!
221
+ * Webの情報は参考程度で実際に計測
222
+
223
+ = 性能検討例
224
+
225
+ * データ:livedoorグルメ\n
226
+ (('note:https://github.com/livedoor/datasets'))
227
+ * 件数:約20万口コミ
228
+ * CPU:Core i7 2.80GHz
229
+
230
+ = 文字数の傾向
231
+
232
+ # coderay sql
233
+ SELECT
234
+ AVG(CHAR_LENGTH(comment)) AS average,
235
+ MIN(CHAR_LENGTH(comment)) as min,
236
+ MAX(CHAR_LENGTH(comment)) as max
237
+ FROM ratings_all;
238
+ -- average: 380.2013
239
+ -- min: 2
240
+ -- max: 6243
241
+
242
+ = %ラーメン%
243
+
244
+ # coderay sql
245
+ SELECT COUNT(*) AS count
246
+ FROM ratings_all
247
+ WHERE comment LIKE "%ラーメン%";
248
+ -- count: 31428
249
+ -- 0.898sec
250
+
251
+ = %ラーメン%の傾向
252
+
253
+ (('tag:center'))実行時間は総件数に比例
254
+
255
+ # RT
256
+
257
+ 総件数, 時間(秒)
258
+
259
+ 1000, 0.01
260
+ 5000, 0.03
261
+ 10000, 0.05
262
+ 100000, 0.50
263
+ 205832, 0.89
264
+
265
+ = AND
266
+
267
+ # coderay sql
268
+ SELECT COUNT(*) AS count
269
+ FROM ratings_all
270
+ WHERE
271
+ comment LIKE "%ラーメン%" AND
272
+ comment LIKE "%焼き肉%";
273
+ -- count: 69
274
+ -- 1.01sec
275
+
276
+ = ANDの傾向
277
+
278
+ (('tag:center'))条件数1の場合とあまり変わらない
279
+
280
+ # RT
281
+
282
+ 総件数, 時間(秒), 条件数1
283
+
284
+ 1000, 0.01, 0.01
285
+ 5000, 0.03, 0.03
286
+ 10000, 0.06, 0.05
287
+ 100000, 0.57, 0.50
288
+ 205832, 1.01, 0.89
289
+
290
+ = OR
291
+
292
+ # coderay sql
293
+ SELECT COUNT(*) AS count
294
+ FROM ratings_all
295
+ WHERE
296
+ comment LIKE "%ラーメン%" OR
297
+ comment LIKE "%焼き肉%";
298
+ -- count: 31994
299
+ -- 1.37sec
300
+
301
+ = ORの傾向
302
+
303
+ (('tag:center'))2倍いかないくらいには増える
304
+
305
+ # RT
306
+
307
+ 総件数, 時間(秒), 条件数1
308
+
309
+ 1000, 0.02, 0.01
310
+ 5000, 0.05, 0.03
311
+ 10000, 0.09, 0.05
312
+ 100000, 0.77, 0.50
313
+ 205832, 1.37, 0.89
314
+
315
+ = 考察
316
+
317
+ * 自分たちのデータ量は?
318
+ * 各レコードのテキストサイズ
319
+ * 総件数
320
+ * どのくらい性能が必要?
321
+ * 1リクエストのレスポンスタイム
322
+ * 単位時間あたりの処理数
323
+
324
+ = 考察例
325
+
326
+ * 自分たちのデータ量は?
327
+ * 各テキストサイズ:400文字くらい\n
328
+ (('note:(データセットと同じくらい)'))
329
+ * 総件数:2,3万くらい
330
+ * どのくらい性能が必要?
331
+ * s/req: 0.5秒以内
332
+ * queries/s: 10
333
+
334
+ = 実行時間
335
+
336
+ (('tag:center'))0.2秒以内には終わりそう
337
+
338
+ # RT
339
+
340
+ 総件数, 時間(秒)
341
+
342
+ 10000, 0.05
343
+ 100000, 0.50
344
+
345
+ = スループット
346
+
347
+ * 1クエリー0.2秒
348
+ * 1秒で5クエリー
349
+ * CPUコア2つで10qpsいけそう
350
+
351
+ (('tag:center'))(('note:(実際は他の条件も加わる→もっと時間がかかるはず)'))
352
+
353
+ = 考察結果は?
354
+
355
+ * LIKEで十分?
356
+ * 機能面と性能面を検討
357
+ * MySQLでLIKEで日本語全文検索!\n
358
+ (('note:(全文検索エンジンが必要ないなら使わなくてよい)'))
359
+ * LIKEだと不十分?
360
+ * 機能面?性能面?
361
+ * 別の選択肢を検討
362
+
363
+ = 別の選択肢
364
+
365
+ * MySQLベースの全文検索機能
366
+ * 全文検索サーバーと連携
367
+
368
+ = 全文検索機能のスキーマ
369
+
370
+ # coderay sql
371
+ CREATE TABLE ratings_all_index (
372
+ comment TEXT,
373
+ FULLTEXT INDEX (comment)
374
+ -- ↑を追加するだけ
375
+ ) DEFAULT CHARSET=utf8mb4;
376
+
377
+ = 全文検索機能の検索方法
378
+
379
+ # coderay sql
380
+ SELECT COUNT(*) AS count
381
+ FROM ratings_all_index
382
+ WHERE
383
+ MATCH (comment)
384
+ AGAINST ("+ラーメン +焼き肉"
385
+ IN BOOLEAN MODE);
386
+
387
+ = 全文検索機能のよいところ
388
+
389
+ * 簡単!
390
+ * 高速な検索!
391
+ * インデックスを使った検索\n
392
+ (('note:(LIKEは逐次検索)'))
393
+ * MySQLとよく統合されている
394
+ * データ登録→インデックス自動更新
395
+ * トランザクションにも対応
396
+
397
+ = 全文検索機能の悪いところ
398
+
399
+ * 日本語未対応
400
+ * 更新が遅い
401
+
402
+ = 日本語未対応
403
+
404
+ * 対策
405
+ * アプリケーション側で前処理\n
406
+ (('note:参考:MySQL Casual Talks Vol.4'))\n
407
+ (('note:「MySQL-5.6で始める全文検索 〜InnoDB FTS編〜」'))\n
408
+ (('note:http://www.slideshare.net/y-ken/my-sql-56innodb-fts'))
409
+ * トレードオフ
410
+ * インフラの管理コストと\n
411
+ アプリのメンテコスト\n
412
+ (('note:(簡単に使えるというメリットは減る)'))
413
+
414
+ = 更新が遅い
415
+
416
+ * ベンチマーク結果
417
+ * 前述のスライドを参照
418
+ * 対策
419
+ * 速いディスクを使う
420
+ * あまり更新しない
421
+ * 検討ポイント
422
+ * どのくらい更新があるか
423
+
424
+ = 全文検索機能のまとめ
425
+
426
+ * データは安全
427
+ * トランザクションを使える
428
+ * レプリケーションもできる
429
+ * 検索は速い・更新は遅い
430
+ * 日本語対応にはひと手間必要
431
+
432
+ = 全文検索機能を使う?
433
+
434
+ * そこそこのデータ量がある
435
+ * アプリ側のひと手間を\n
436
+ 許せるならアリ
437
+ * 更新が少ないならアリ
438
+
439
+ = 突然の質問
440
+
441
+ MySQLの特徴と\n
442
+ 言えば?\n
443
+ (('note:(期待する答えがでるまで聞きます)'))
444
+
445
+ = プラグイン機能
446
+
447
+ * 一部の機能を追加できる
448
+ * ストレージエンジン・UDF・…
449
+ * 全文検索機能も追加できる
450
+
451
+ = 全文検索プラグイン
452
+
453
+ Mroonga
454
+
455
+ = Mroongaのスキーマ
456
+
457
+ # coderay sql
458
+ CREATE TABLE ratings_all_index (
459
+ comment TEXT,
460
+ FULLTEXT INDEX (comment)
461
+ -- ↑と↓を追加するだけ
462
+ ) ENGINE=Mroonga
463
+ DEFAULT CHARSET=utf8mb4;
464
+
465
+ = Mroongaの検索方法
466
+
467
+ # coderay sql
468
+ -- MySQL標準の方法と同じ
469
+ SELECT COUNT(*) AS count
470
+ FROM ratings_all_index
471
+ WHERE
472
+ MATCH (comment)
473
+ AGAINST ("+ラーメン +焼き肉"
474
+ IN BOOLEAN MODE);
475
+
476
+ = Mroongaのよいところ
477
+
478
+ * 簡単!
479
+ * 高速な検索と更新!
480
+ * 日本語対応!(('note:(開発者が日本人)'))
481
+ * MySQLとそれなりに統合
482
+ * データ登録→インデックス自動更新
483
+
484
+ = Mroongaの悪いところ
485
+
486
+ * トランザクション非対応
487
+ * NULL非対応
488
+ * 別途インストールが必要
489
+
490
+ = トランザクション非対応
491
+
492
+ * 対策
493
+ * レプリケーションをして、\n
494
+ マスターをInnoDB、\n
495
+ スレーブをMroongaにする
496
+ * 参考
497
+ * 多くの全文検索システムは\n
498
+ トランザクション非対応
499
+
500
+ = NULL非対応
501
+
502
+ * 対策
503
+ * NULLを使わない
504
+
505
+ = 別途インストールが必要
506
+
507
+ * 対策:パッケージを使う
508
+ * パッケージ
509
+ * CentOS 6, 7
510
+ * Fedora(公式)
511
+ * Debian/Ubuntu 安定版リリース
512
+ * Windows
513
+ * OS X(Homebrew/MacPorts)
514
+
515
+ = Mroongaのまとめ
516
+
517
+ * 日本語対応
518
+ * 検索も更新も速い
519
+ * インストール作業が必要
520
+ * 使うときは簡単
521
+
522
+ = Mroongaを使う?
523
+
524
+ * そこそこのデータ量がある
525
+ * 更新が多い
526
+ * トランザクションとNULLが\n
527
+ なくてもよいならアリ
528
+ * 開発者を信頼できるならアリ
529
+
530
+ = ここまでの話のポイント
531
+
532
+ 全文検索方法の\n
533
+ 詳細を\n
534
+ 知らなくても\n
535
+ 使える
536
+
537
+ = 別の選択肢
538
+
539
+ * (('del:MySQLベースの全文検索機能'))
540
+ * 全文検索サーバーと連携
541
+
542
+ = 全文検索サーバー
543
+
544
+ * Solr
545
+ * Elasticsearch
546
+ * Groonga
547
+ * Sphinx(('note:(http://sphinxsearch.com/)'))
548
+ * Amazon CloudSearch
549
+
550
+ = 違い
551
+
552
+ * 機能面
553
+ * 全文検索初心者が使う分には\n
554
+ どれも不足なし
555
+ * 性能面
556
+ * まあまあかそこそこのデータ量\n
557
+ (('note:(1台のサーバーでさばける量)'))\n
558
+ ならどれも十分な性能
559
+
560
+ = 機能面:補足1
561
+
562
+ * 全文検索対応の進め方1
563
+ * いきなりカンペキを目指さない
564
+ * まず動かして実際に試す
565
+ * 改良したいという箇所に気づく
566
+ * 1つずつ改良しながら\n
567
+ 仕組みを学んでいく
568
+
569
+ = 機能面:補足2
570
+
571
+ * 全文検索対応の進め方2
572
+ * 詳しい人に相談
573
+ * MySQLユーザ会のブースへ!
574
+
575
+ = 連携
576
+
577
+ # image
578
+ # src = images/integrate-with-full-text-server.svg
579
+ # relative_width = 90
580
+
581
+ = アプリの動作:更新
582
+
583
+ # image
584
+ # src = images/full-text-server-update.svg
585
+ # relative_width = 90
586
+
587
+ = アプリの動作:更新
588
+
589
+ * 更新時
590
+ * トランザクション開始
591
+ * MySQLにデータ投入
592
+ * 全文検索サーバーにもデータ投入
593
+ * トランザクション終了
594
+ * ロールバックはアプリの仕事
595
+
596
+ = アプリの動作:検索
597
+
598
+ # image
599
+ # src = images/full-text-server-search.svg
600
+ # relative_width = 90
601
+
602
+ = アプリの動作:検索
603
+
604
+ * 検索時
605
+ * 全文検索サーバーで検索
606
+ * 見つかったレコードIDを条件に\n
607
+ MySQLで検索
608
+ * スコアとか結果をマージして表示
609
+ * JOINはアプリの仕事
610
+ * 全文検索と他の検索を混ぜるときは\n
611
+ どうするか考えてみよう
612
+
613
+ = アプリの開発
614
+
615
+ * 実装
616
+ * ライブラリーを使う
617
+ * 更新・検索をサポートしてくれる
618
+ * テスト
619
+ * 各自全文検索サーバーを用意
620
+ * 開発環境の用意が面倒になる\n
621
+ (('note:(VagrantやDockerを使うといいかも)'))
622
+
623
+ = インフラ
624
+
625
+ * MySQLとは別に\n
626
+ 全文検索サーバーを管理
627
+ * パラメーターの設定
628
+ * 落ちた時どうする?
629
+ * システムが必要なリソース増加
630
+ * 例:専用マシンを追加
631
+
632
+ = 連携したときのよいところ
633
+
634
+ * SQLが苦手なクエリーを\n
635
+ 効率よく実現できる
636
+ * ファセット・タグ検索
637
+ * チューニングできる
638
+ * トークナイザーを変える
639
+ * フレーズ検索→近傍検索
640
+ * トークンの正規化方法を変える等…
641
+
642
+ = トークナイザー
643
+
644
+ * 空白区切り(('note:(英語やタグの検索に便利)'))
645
+ * N-gram
646
+ * 適合率↓検索漏れ↓
647
+ * アルファベットの文章で遅い
648
+ * 形態素解析
649
+ * 適合率↑検索漏れ↑
650
+ * 新語に弱い
651
+
652
+ = N-gram
653
+
654
+ * 文字種が多い言語に向いている
655
+ * 日本語
656
+ * 文字種が少ないと効率が悪い
657
+ * 英語
658
+ * 文字種により挙動を変えて改善
659
+ * 日本語:N-gram、英語:単語単位
660
+
661
+ = 形態素解析
662
+
663
+ * 区切り方が複数パターンある
664
+ * 全パターンインデックスに登録
665
+ * ↑は検索漏れは↓が適合率も↓かも
666
+ * 検索時に使い分ける
667
+ * ヒットしなかったら\n
668
+ N-gramにフォールバック
669
+
670
+ = フレーズ検索→近傍検索
671
+
672
+ * 「日野でラーメン」で検索
673
+ * ○「日野でラーメン」
674
+ * ×「日野でみそラーメン」
675
+ * 「日野 ... ラーメン」で検索
676
+ * ○「日野でみそラーメン」
677
+ * ○「日野で塩ラーメン」
678
+
679
+ = 正規化
680
+
681
+ * 英単語のステミング
682
+ * 濁点を無視する?しない?
683
+ * すし=ずし
684
+ * ハハ=パパ=ババ
685
+ * 同義語はいつ展開?
686
+
687
+ = 連携したときのよいところ
688
+
689
+ * SQLが苦手なクエリーを\n
690
+ 効率よく実現できる
691
+ * ファセット・タグ検索
692
+ * チューニングできる
693
+ * トークナイザーを変える
694
+ * フレーズ検索→近傍検索
695
+ * トークンの正規化方法を変える等…
696
+
697
+ = 連携したときの悪いところ
698
+
699
+ * メンテナンスコストが増える
700
+ * 開発面でもインフラ面でも
701
+ * 必要なリソースが増える
702
+ * ランニングコストが増える
703
+ * ある程度全文検索の知識が必要
704
+
705
+ = サーバー連携のまとめ
706
+
707
+ * 日本語対応
708
+ * 検索も更新も速い
709
+ * チューニングできる
710
+ * 導入・運用は手間が増える
711
+ * 使うときも手間が増える
712
+
713
+ = 全文検索サーバーを使う?
714
+
715
+ * そこそこのデータ量がある
716
+ * チューニングしたい
717
+ * 導入・運用・開発の手間増加が\n
718
+ 割に合うならアリ
719
+
720
+ = 参考:PostgreSQL
721
+
722
+ * 日本語未対応
723
+ * プラグインで対応
724
+ * 完全転置インデックスではない
725
+ * インデックスだけ使うと誤検出あり
726
+ * ↑の後にLIKEで誤検出を除去
727
+
728
+ = まとめ
729
+
730
+ * LIKEで十分ならLIKEでいい
731
+ * LIKEで不足ならMroonga
732
+ * それでも不足なら
733
+ * マスターデータはMySQL
734
+ * 検索対象は全文検索サーバー
735
+
736
+ = つまり!
737
+
738
+ いろいろ考えると\n
739
+ 日本語の全文検索も\n
740
+ MySQLがいいね!\n
741
+ (('note:MySQLが役に立つね'))
742
+
743
+ = お知らせ1
744
+
745
+ * MySQLユーザ会ブースあり
746
+ * 隣はOracleのMySQLの人たち
747
+ * 17:15-別のMySQL枠あり
748
+ * OracleのMySQLの人の話
749
+
750
+ = お知らせ2
751
+
752
+ * MariaDBにMronogaバンドル!
753
+ * 10.0.15から組み込み!
754
+ * 別途インストールしなくてよい!
755
+
756
+ = お知らせ3
757
+
758
+ * 検索エンジンについて知りたい
759
+ * 「検索エンジン自作入門」
760
+ * いい肉の日に渋谷で\n
761
+ Groongaイベント!
762
+ * 「いい肉 Groonga」で検索
763
+ * 自作本のサイン会をやるよ!
764
+
765
+ = お知らせ4
766
+
767
+ * Groongaをもっと知りたい
768
+ * Groongaドキュメント読書会
769
+ * 詳細は↑で検索
770
+ * Mroongaが使っている\n
771
+ 全文検索エンジンの理解を深める会
772
+ * 1,2ヶ月に1回開催