rabbit-slide-kou-php-conference-2017 2017.10.08.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ec4cae3a085fc043e16dd908ef24ffced568281c
4
+ data.tar.gz: 8915e502b0374beb084d775d5ac7ac5d32cb8de3
5
+ SHA512:
6
+ metadata.gz: 82e3b43f0b8d7e0307ebcbb7906a4a92378b1c79ac3b60b94361b85ce177cfd0856b5402f02428279b0e1add8f365924bb8daabe899f4e463bd58988ab5fa0a2
7
+ data.tar.gz: 1a0d1fb95de9f6b3a38ff333cbe30420100c7d7a67a7dab7d8c50d91e5405d67230216da765df7fb0f1602249aa805530992b9e3774a1aeb25fc8d2b2d625bf8
data/.rabbit ADDED
@@ -0,0 +1 @@
1
+ php-document-fast-full-text-search-system-with-postgresql-and-pgroonga.rab
data/README.rd ADDED
@@ -0,0 +1,48 @@
1
+ = PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム
2
+
3
+ PHPマニュアルは日本語にも翻訳されていますが、検索機能が限定的なため、せっかくの説明を活用しきれません。基本の検索機能は関数やクラス名の検索機能しかないため「正規表現」で正規表現の使い方を検索できません。サイト内検索機能では「@」でエラー制御演算子を検索できません。
4
+
5
+ この講演ではPHPマニュアルをより活用するためのPHPマニュアル高速全文検索システムを紹介します。このシステムはPostgreSQLとPGroongaを利用して実現しています。
6
+
7
+ == ライセンス
8
+
9
+ === スライド
10
+
11
+ CC BY-SA 4.0
12
+
13
+ 原著作者名は以下の通りです。
14
+
15
+ * 須藤功平(またはKouhei Sutou)
16
+
17
+ === 画像
18
+
19
+ ==== Groonga・Mroonga・PGroongaのロゴ
20
+
21
+ CC BY 3.0
22
+
23
+ 原著作者名は以下の通りです。
24
+
25
+ * Groongaプロジェクト
26
+ * Mroongaプロジェクト
27
+ * PGroongaプロジェクト
28
+
29
+ == 作者向け
30
+
31
+ === 表示
32
+
33
+ rake
34
+
35
+ === 公開
36
+
37
+ rake publish
38
+
39
+ == 閲覧者向け
40
+
41
+ === インストール
42
+
43
+ gem install rabbit-slide-kou-php-conference-2017
44
+
45
+ === 表示
46
+
47
+ rabbit rabbit-slide-kou-php-conference-2017.gem
48
+
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require "rabbit/task/slide"
2
+
3
+ # Edit ./config.yaml to customize meta data
4
+
5
+ spec = nil
6
+ Rabbit::Task::Slide.new do |task|
7
+ spec = task.spec
8
+ spec.files += Dir.glob("images/**/*.*")
9
+ # spec.files -= Dir.glob("private/**/*.*")
10
+ spec.add_runtime_dependency("rabbit-theme-groonga")
11
+ end
12
+
13
+ desc "Tag #{spec.version}"
14
+ task :tag do
15
+ sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
16
+ sh("git", "push", "--tags")
17
+ end
data/config.yaml ADDED
@@ -0,0 +1,26 @@
1
+ ---
2
+ id: php-conference-2017
3
+ base_name: php-document-fast-full-text-search-system-with-postgresql-and-pgroonga
4
+ tags:
5
+ - rabbit
6
+ - php
7
+ - postgresql
8
+ - pgroonga
9
+ - phpcon2017
10
+ presentation_date: '2017-10-08'
11
+ version: 2017.10.08.0
12
+ licenses:
13
+ - CC BY 3.0
14
+ - CC BY-SA 4.0
15
+ slideshare_id: phpconference2017
16
+ speaker_deck_id:
17
+ ustream_id:
18
+ vimeo_id:
19
+ youtube_id:
20
+ author:
21
+ markup_language: :rd
22
+ name: Kouhei Sutou
23
+ email: kou@clear-code.com
24
+ rubygems_user: kou
25
+ slideshare_user: kou
26
+ speaker_deck_user:
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,871 @@
1
+ = PostgreSQLとPGroongaで\n作る\nPHPマニュアル\n高速全文検索システム
2
+
3
+ : author
4
+ 須藤功平
5
+ : institution
6
+ クリアコード
7
+ : content-source
8
+ PHPカンファレンス2017
9
+ : date
10
+ 2017-10-08
11
+ : start-time
12
+ 2017-10-08T11:00:00+09:00
13
+ : end-time
14
+ 2017-10-08T12:00:00+09:00
15
+ : theme
16
+ .
17
+
18
+ = PHPマニュアル
19
+
20
+ # image
21
+ # src = images/php-manual-ja.png
22
+ # relative_width = 80
23
+
24
+ (('tag:center'))
25
+ http://php.net/manual/ja/
26
+
27
+ = @で検索
28
+
29
+ # image
30
+ # src = images/php-manual-ja-search-by-at.png
31
+ # relative_width = 80
32
+
33
+ (('tag:center'))
34
+ @:エラー制御演算子
35
+
36
+ = @でnot found
37
+
38
+ # image
39
+ # src = images/php-manual-ja-search-by-at-not-found.png
40
+ # relative_width = 80
41
+
42
+ (('tag:center'))
43
+ 関数・クラス・例外のみ検索対象
44
+
45
+ = 全文検索あり!
46
+
47
+ # image
48
+ # src = images/php-manual-ja-full-text-search-link.png
49
+ # relative_height = 80
50
+
51
+ (('tag:center'))
52
+ Googleカスタム検索
53
+
54
+ = @でnot found
55
+
56
+ # image
57
+ # src = images/php-manual-ja-full-text-search-by-at-not-found.png
58
+ # relative_width = 80
59
+
60
+ (('tag:center'))
61
+ Googleは自然言語向けだから
62
+
63
+ = マニュアル検索
64
+
65
+ * 自然言語向けと傾向が違う
66
+ * @:自然言語ではノイズ\n
67
+ (('note:特に日本語ではノイズ'))
68
+ * @:マニュアルでは重要語
69
+ * プログラミング言語用の\n
70
+ チューニングが必要
71
+ * 🔍欲しい情報が見つかる!
72
+
73
+ = マニュアル\n検索システムの\n作り方
74
+
75
+ = PHP\n+\nPostgreSQL
76
+
77
+ = PostgreSQLと全文検索
78
+
79
+ * LIKE:組込機能
80
+ * textsearch:組込機能
81
+ * pg_trgm:標準添付
82
+ * アーカイブには含まれている
83
+ * 別途インストールすれば使える
84
+
85
+ = LIKE
86
+
87
+ * 少ないデータ
88
+ * 十分実用的
89
+ * 400文字×20万件くらいなら1秒とか
90
+ * 少なくないデータ
91
+ * 性能問題アリ
92
+
93
+ = PHPマニュアルのデータ
94
+
95
+ # RT
96
+
97
+ 件数, 13095
98
+ 平均文字数, 871文字
99
+
100
+ = PHPマニュアルでLIKE
101
+
102
+ * 👍速度は十分実用的
103
+ * (({LIKE '%@%'}))で約100ms
104
+ * 👎それっぽい順のソート不可
105
+ * 全文検索ではソート順が重要
106
+ * ユーザーは先頭n件しか見ない
107
+
108
+ = textsearch
109
+
110
+ * インデックスを作るので速い
111
+ * 言語毎にモジュールが必要
112
+ * 英語やフランス語などは組込
113
+ * 日本語は別途必要
114
+ * 日本語用モジュール
115
+ * 公式にはメンテナンスされていない\n
116
+ (('note:forkして動くようにしている人はいる'))
117
+
118
+ = pg_trgm
119
+
120
+ * インデックスを作るので速い
121
+ * 注:ヒット件数が増えると遅い
122
+ * 注:テキスト量が多いと遅い
123
+ * 注:1,2文字の検索は遅い(('note:(米・日本)'))
124
+
125
+ * 日本語を使うにはひと工夫必要
126
+ * C.UTF-8を使う
127
+ * ソースを変更してビルド
128
+
129
+ = プラグイン
130
+
131
+ * pg_bigm
132
+ * pg_trgmの日本語対応強化版
133
+ * それっぽい順のソート不可
134
+ * PGroonga
135
+ * 本気の全文検索エンジンを利用
136
+ * 速いし日本語もバッチリ!
137
+ * それっぽい順のソート可
138
+
139
+ = ベンチマーク:pg_bigm
140
+
141
+ # image
142
+ # src = images/search-pg-bigm.pdf
143
+ # relative_height = 100
144
+
145
+ = ベンチマーク:PGroonga
146
+
147
+ # image
148
+ # src = images/search-pgroonga-pg-bigm.pdf
149
+ # relative_height = 100
150
+
151
+ = PostgreSQLで全文検索システム
152
+
153
+ * PostgreSQLで全文検索
154
+ * PGroongaがベスト!💯
155
+ * PGroonga
156
+ * 高速
157
+ * 日本語対応
158
+ * それっぽい順でソート可
159
+
160
+ = PHP document search
161
+
162
+ # image
163
+ # src = images/php-document-search.png
164
+ # relative_height = 80
165
+
166
+ (('tag:center'))
167
+ PHP + PostgreSQL + PGroonga
168
+
169
+ = 基本機能
170
+
171
+ * 高速全文検索+ソート
172
+ * 検索キーワードハイライト
173
+ * キーワード周辺テキスト表示
174
+
175
+ = 高度な機能
176
+
177
+ * オートコンプリート
178
+ * ローマ字対応(seiki→正規表現)
179
+ * 類似マニュアル検索
180
+ * 同義語展開
181
+ * 「@」→「@ OR エラー制御演算子」
182
+
183
+ = 作り方:ツール
184
+
185
+ * フレームワーク
186
+ * Laravel
187
+ * RDBMS
188
+ * PostgreSQL
189
+ * 高速日本語全文検索機能
190
+ * PGroonga
191
+
192
+ = 作り方:インストール
193
+
194
+ * Laravel
195
+ * 省略
196
+ * PostgreSQL
197
+ * パッケージで
198
+ * PGroonga
199
+ * パッケージで\n
200
+ (('tag:x-small:https://pgroonga.github.io/ja/install/'))
201
+
202
+ = 初期化:Laravel
203
+
204
+ # coderay console
205
+
206
+ % laravel new php-document-search
207
+ % cd php-document-search
208
+ % editor .env
209
+
210
+ = 初期化:データベース
211
+
212
+ # coderay console
213
+
214
+ % sudo -u postgres -H \
215
+ createdb php_document_search
216
+
217
+ = 初期化:PGroonga
218
+
219
+ # rouge sql
220
+ -- ↓を実行する必要がある
221
+ CREATE EXTENSION pgroonga;
222
+
223
+ = 初期化:PGroonga
224
+
225
+ (('tag:center'))
226
+ マイグレーションファイル作成
227
+
228
+ # coderay console
229
+
230
+ % php artisan \
231
+ make:migration enable_pgroonga
232
+
233
+ = マイグレーション
234
+
235
+ # coderay php
236
+
237
+ public function up()
238
+ {
239
+ DB::statement("CREATE EXTENSION pgroonga;");
240
+ // CREATE EXTENSION IF NOT EXISTS ...の方がよい
241
+ }
242
+
243
+ public function down()
244
+ {
245
+ DB::statement("DROP EXTENSION pgroonga;");
246
+ }
247
+
248
+ = モデル作成
249
+
250
+ * マニュアルをモデルにする
251
+ * 名前:(({Entry}))
252
+ * 1ページ1インスタンス
253
+
254
+ = モデル作成
255
+
256
+ # coderay console
257
+
258
+ % php artisan \
259
+ make:model \
260
+ --migration \
261
+ --controller \
262
+ --resource \
263
+ Entry
264
+
265
+ = マイグレーション
266
+
267
+ # coderay php
268
+
269
+ Schema::create("entries", function ($table) {
270
+ $table->increments("id");
271
+ $table->text("url");
272
+ $table->text("title");
273
+ $table->text("content");
274
+ // PGroongaインデックス(デフォルト:全文検索用)
275
+ // 主キー(id)も入れるのが大事!
276
+ // それっぽい順のソートで必要
277
+ $table->index(
278
+ ["id", "title", "content"], null, "pgroonga");
279
+ });
280
+
281
+ = データ登録
282
+
283
+ (1) PHPのドキュメントを\n
284
+ ローカルで生成
285
+ * PHPのドキュメントの作り方\n
286
+ http://doc.php.net/tutorial/
287
+ * フィードバックチャンスが\n
288
+ いろいろあったよ!
289
+ (2) ページ毎にPostgreSQLに挿入
290
+
291
+ = コマンド作成
292
+
293
+ # coderay console
294
+
295
+ % php artisan \
296
+ make:command \
297
+ --command=doc:register \
298
+ RegisterDocuments
299
+
300
+ = 登録コマンド実装(一部)
301
+
302
+ # coderay php
303
+
304
+ public function handle()
305
+ {
306
+ foreach (glob("public/doc/*.html") as $html_path) {
307
+ $document = new \DOMDocument();
308
+ @$document->loadHTMLFile($html_path);
309
+ $xpath = new \DOMXPath($document);
310
+ $entry = new Entry();
311
+ $entry->url = "/doc/" . basename($html_path);
312
+ // XPathでテキスト抽出
313
+ $this->extract_title($entry, $xpath);
314
+ $this->extract_content($entry, $xpath);
315
+ $entry->save();
316
+ }
317
+ }
318
+
319
+ = 登録
320
+
321
+ # coderay console
322
+
323
+ % php artisan doc:register
324
+
325
+ = 検索用コントローラー
326
+
327
+ # coderay php
328
+
329
+ public function index(Request $request)
330
+ {
331
+ $query = $request["query"];
332
+ $entries = Entry::query()
333
+ // ↓はモデルに作る(後述)
334
+ ->fullTextSearch($query)
335
+ ->limit(10)
336
+ ->get();
337
+ return view("entry.search.index",
338
+ ["entries" => $entries,
339
+ "query" => $query]);
340
+ }
341
+
342
+ = 検索対象モデル
343
+
344
+ # coderay php
345
+
346
+ public function
347
+ scopeFullTextSearch($query, $search_query)
348
+ {
349
+ if ($search_query) {
350
+ return ...; // クエリーがあったら検索
351
+ } else {
352
+ return ...; // なかったら適当に返す(省略)
353
+ }
354
+ }
355
+
356
+ = 検索対象モデル:検索
357
+
358
+ # coderay php
359
+
360
+ return $query
361
+ ->select("id", "url")
362
+ // それっぽさの度合い
363
+ ->selectRaw("pgroonga_score(entries) AS score")
364
+ // キーワードハイライト
365
+ ->highlightHTML("title", $search_query)
366
+ // キーワード周辺のテキスト(キーワードハイライト付き)
367
+ ->snippetHTML("content", $search_query)
368
+ // タイトルと本文を全文検索(タイトルの方が重要)
369
+ ->whereRaw("title &@~ ? OR content &@~ ?",
370
+ [">($search_query)", $search_query])
371
+ // それっぽい順に返す
372
+ ->orderBy("score", "DESC");
373
+
374
+ = キーワードハイライト
375
+
376
+ # coderay php
377
+
378
+ public function scopeHighlightHTML($query,
379
+ $column,
380
+ $search_query)
381
+ {
382
+ return $query
383
+ // PGroonga提供ハイライト関数
384
+ ->selectRaw("pgroonga_highlight_html($column, " .
385
+ // PGroonga提供クエリーからキーワードを抽出する関数
386
+ "pgroonga_query_extract_keywords(?)) " .
387
+ "AS highlighted_$column",
388
+ [$search_query]);
389
+ }
390
+
391
+ = 検索結果
392
+
393
+ # coderay php
394
+
395
+ <div class="entries">
396
+ @foreach ($entries as $entry)
397
+ <a href="{{ $entry->url }}">
398
+ <h4>
399
+ {{-- マークアップ済み! --}}
400
+ {!! $entry->highlighted_title !!}
401
+ <span class="score">{{ $entry->score }}</span>
402
+ </h4>
403
+ {{-- 周辺テキストはtext[](後で補足) --}}
404
+ @foreach ($entry->content_snippets as $snippet)
405
+ <pre class="snippet">{!! $snippet !!}</pre>
406
+ @endforeach
407
+ </a>
408
+ @endforeach
409
+ </div>
410
+
411
+ = 検索対象モデル:配列
412
+
413
+ # coderay php
414
+
415
+ public function getContentSnippetsAttribute($value)
416
+ { // PostgreSQLは配列をサポートしているがPDOは未サポート
417
+ // '["...","..."]'という文字列になるのでそれを配列に変換
418
+ // ※これは回避策なのでPDOに配列サポートを入れたい!
419
+ return array_map(
420
+ function ($e) {
421
+ // 「"」が「\"」になっているので戻す
422
+ return preg_replace('/\\\\(.)/', '$1', $e);
423
+ },
424
+ explode('","', substr($value, 2, -2)));
425
+ }
426
+
427
+ = 高速日本語全文検索!
428
+
429
+ # image
430
+ # src = images/php-document-search-search.png
431
+ # relative_height = 100
432
+
433
+ = オートコンプリート
434
+
435
+ * 必要なもの
436
+ * 候補用テーブル
437
+ * 候補のヨミガナ(カタカナ)
438
+ * PGroonga!!!
439
+
440
+ = モデル作成
441
+
442
+ # coderay console
443
+
444
+ % php artisan \
445
+ make:model \
446
+ --migration \
447
+ --controller \
448
+ --resource \
449
+ Term
450
+
451
+ = マイグレーション:カラム
452
+
453
+ # coderay php
454
+
455
+ Schema::create("terms", function ($table) {
456
+ $table->increments("id");
457
+ $table->text("term");
458
+ $table->text("label");
459
+ $table->text("reading"); // 本当は配列にしたい
460
+ $table->timestamps();
461
+ // インデックス定義(後述)
462
+ });
463
+
464
+ = マイグレーション\nインデックス1
465
+
466
+ # coderay php
467
+
468
+ $table->index([
469
+ // ヨミガナに対する前方一致RK検索用
470
+ // RK:ローマ字・カナ(後述)
471
+ DB::raw("reading " .
472
+ "pgroonga_text_term_search_ops_v2"),
473
+ ], null, "pgroonga");
474
+
475
+ = マイグレーション\nインデックス2
476
+
477
+ # coderay php
478
+
479
+ // 候補に対するゆるい全文検索用(中間一致用)
480
+ DB::statement(
481
+ "CREATE INDEX terms_term_index " .
482
+ "ON terms " .
483
+ "USING pgroonga (term) " .
484
+ // ↓がポイント
485
+ // ※LaravelがWITHを未サポートなのでSQLで書いている
486
+ // ※回避策なのでLaravelにWITHサポートを入れたい!
487
+ "WITH (tokenizer='TokenBigramSplitSymbolAlphaDigit')");
488
+
489
+ = 前方一致RK検索
490
+
491
+ * 日本語特化の前方一致検索
492
+ * ローマ字・ひらがな・カタカナで\n
493
+ カタカナを前方一致検索できる
494
+ * gy→ギュウニュウ
495
+ * ぎ→ギュウニュウ
496
+ * ギ→ギュウニュウ
497
+
498
+ = 候補モデル:検索
499
+
500
+ # coderay php
501
+
502
+ public function scopeComplete($query, $search_query)
503
+ {
504
+ return $query
505
+ ->select("label")
506
+ ->highlightHTML("label", $search_query)
507
+ // 前方一致RK検索
508
+ ->whereRaw("reading &^~ :query OR " .
509
+ // ゆるい全文検索
510
+ "term &@~ :query",
511
+ ["query" => $search_query])
512
+ ->orderBy("label")
513
+ ->limit(10);
514
+ }
515
+
516
+ = コントローラー
517
+
518
+ # coderay php
519
+
520
+ public function index(Request $request)
521
+ {
522
+ $query = $request["query"];
523
+ // モデルに実装した検索処理を呼び出し
524
+ $terms = Term::query()->complete($query);
525
+ $data = [];
526
+ foreach ($terms->get() as $term) {
527
+ $data[] = [
528
+ "value" => $term->label,
529
+ "label" => $term->highlighted_label,
530
+ ];
531
+ }
532
+ // JSONで候補を返す
533
+ return response()->json($data);
534
+ }
535
+
536
+ = UI
537
+
538
+ # coderay javascript
539
+
540
+ $("#query").autocomplete({
541
+ source: function(request, response) {
542
+ $.ajax({
543
+ url: "/terms/", // コントローラー呼び出し
544
+ dataType: "json",
545
+ data: {query: this.term},
546
+ success: response
547
+ });
548
+ }
549
+ }).autocomplete("instance")._renderItem = function(ul, item) {
550
+ return $("<li>")
551
+ .attr("data-value", item.value) // 候補には生データを使う
552
+ .append(item.label) // ハイライトしたデータを表示
553
+ .appendTo(ul);
554
+ };
555
+
556
+ = オートコンプリート!
557
+
558
+ # image
559
+ # src = images/php-document-search.png
560
+ # relative_height = 100
561
+
562
+ = 類似マニュアル検索
563
+
564
+ # image
565
+ # src = images/php-document-search-similar-search.png
566
+ # relative_height = 100
567
+
568
+ = 実現方法
569
+
570
+ * 類似検索用インデックスが必要
571
+ * 自然言語に合わせた処理で精度向上
572
+ * 日本語ならMeCabを活用
573
+ * 類似検索用の演算子を使う
574
+ * 類似検索クエリー\n
575
+ →対象マニュアルのテキスト全体
576
+ * 参考:全文検索クエリー\n
577
+ →キーワード
578
+
579
+ = インデックス作成
580
+
581
+ (('tag:center'))
582
+ マイグレーションファイル作成
583
+
584
+ # coderay console
585
+
586
+ % php artisan \
587
+ make:migration \
588
+ add_similar_search_index
589
+
590
+ = マイグレーション
591
+
592
+ # coderay php
593
+
594
+ public function up()
595
+ { // WITHを使っているのでDB::statementを使用
596
+ DB::statement(
597
+ "CREATE INDEX similar_search_index " .
598
+ "ON entries " .
599
+ // タイトルと内容を合わせたテキストをインデックス
600
+ // 理由1:タイトルも重要→対象に加えて精度向上
601
+ // 理由2:PostgreSQLが全文検索インデックスと
602
+ // 区別できるように
603
+ "USING pgroonga (id, (title || ' ' || content)) " .
604
+ // ポイント:MeCabを使う
605
+ "WITH (tokenizer='TokenMecab')");
606
+ }
607
+
608
+ = 類似検索:スコープ
609
+
610
+ # coderay php
611
+
612
+ public function scopeSimilarSearch($query, $text)
613
+ {
614
+ return $query
615
+ ->select("id", "url", "title")
616
+ ->selectRaw("pgroonga_score(entries) AS score")
617
+ // インデックス定義と同じ式↓を指定すること!
618
+ // title || ' ' || content
619
+ // &@*が類似検索の演算子
620
+ ->whereRaw("(title || ' ' || content) &@* ?",
621
+ [$text])
622
+ ->orderBy("score", "DESC");
623
+ }
624
+
625
+ = 類似検索:インスタンスメソッド
626
+
627
+ # coderay php
628
+
629
+ public function similarEntries()
630
+ {
631
+ return Entries::query()
632
+ // タイトルと内容がクエリー
633
+ ->similarSearch("{$this->title} {$this->content}")
634
+ // 自分自身を除くこと!
635
+ ->where("id", "<>", $this->id)
636
+ // 最も類似している3件のみ取得
637
+ ->limit(3)
638
+ ->get();
639
+ }
640
+
641
+ = 類似検索:使い方
642
+
643
+ # coderay php
644
+
645
+ @foreach ($entries as $entry)
646
+ <ol> {{-- ↓マニュアル毎に類似文書検索 --}}
647
+ @foreach ($entry->similarEntries() as $similarEntry)
648
+ <li>
649
+ <a href="{{ $similarEntry->url }}">
650
+ {{ $similarEntry->title }}
651
+ <span class="score">{{ $similarEntry->score }}</span>
652
+ </a>
653
+ </li>
654
+ @endforeach
655
+ </ol>
656
+ @endforeach
657
+
658
+ = 類似マニュアル検索
659
+
660
+ # image
661
+ # src = images/php-document-search-similar-search.png
662
+ # relative_height = 100
663
+
664
+ = 同義語展開
665
+
666
+ # image
667
+ # src = images/php-document-search-synonym.png
668
+ # relative_height = 100
669
+
670
+ = 実現方法
671
+
672
+ * 同義語管理テーブルを作成
673
+ * 同義語を登録
674
+ * 同義語を展開して検索
675
+
676
+ = モデル作成
677
+
678
+ # coderay console
679
+
680
+ % php artisan \
681
+ make:model \
682
+ --migration \
683
+ --controller \
684
+ --resource \
685
+ Synonym
686
+
687
+ = マイグレーション:カラム
688
+
689
+ # coderay php
690
+
691
+ public function up() {
692
+ Schema::create('synonyms', function ($table) {
693
+ $table->increments('id');
694
+ $table->text('term'); // 展開対象の語
695
+ $table->text('synonym'); // 展開後の語
696
+ // 例:term: @, synonym: @
697
+ // 例:term: @, synonym: エラー制御演算子
698
+ // 「@」→「@ OR エラー制御演算子」
699
+ $table->timestamps();
700
+ // インデックス定義(後述)
701
+ });
702
+ }
703
+
704
+ = マイグレーション\nインデックス
705
+
706
+ # coderay php
707
+
708
+ $table->index(
709
+ // termで完全一致できるようにする設定
710
+ [DB::raw(
711
+ "term pgroonga_text_term_search_ops_v2")],
712
+ null,
713
+ "pgroonga");
714
+
715
+ = 同義語登録
716
+
717
+ (('tag:center'))
718
+ シーダー作成
719
+
720
+ # coderay console
721
+
722
+ % php artisan \
723
+ make:seeder \
724
+ SynonymsTableSeeder
725
+
726
+ = シーダー
727
+
728
+ # coderay php
729
+
730
+ public function run()
731
+ {
732
+ $synonyms = [
733
+ // @そのもので検索させないならこれはいらない
734
+ ["term" => "@", "synonym" => "@"],
735
+ ["term" => "@",
736
+ // synonymでは演算子を使える
737
+ // ">": 重要度を上げる演算子
738
+ "synonym" => ">エラー制御演算子"],
739
+ ];
740
+ DB::table("synonyms")->insert($synonyms);
741
+ }
742
+
743
+ = 動作確認
744
+
745
+ # coderay sql
746
+
747
+ SELECT pgroonga_query_expand(
748
+ 'synonyms', -- テーブル名
749
+ 'term', -- 展開対象語のカラム名
750
+ 'synonym', -- 展開後の語のカラム名
751
+ '@'); -- 展開対象のクエリー
752
+ -- pgroonga_query_expand
753
+ -- ------------------------------
754
+ -- ((@) OR (>エラー制御演算子))
755
+ -- (1 row)
756
+
757
+ = 検索
758
+
759
+ # coderay php
760
+
761
+ whereRaw("title &@~ ? OR content &@~ ?",
762
+ [">({$search_query})", $search_query]);
763
+ // ↓クエリーをpgroonga_query_expand()で展開して利用
764
+ whereRaw(
765
+ "title &@~ pgroonga_query_expand(?, ?, ?, ?) OR " .
766
+ "content &@~ pgroonga_query_expand(?, ?, ?, ?)",
767
+ ["synonyms", "term", "synonym", ">({$search_query})",
768
+ "synonyms", "term", "synonym", $search_query]);
769
+
770
+ = 同義語展開
771
+
772
+ # image
773
+ # src = images/php-document-search-synonym.png
774
+ # relative_height = 100
775
+
776
+ = おさらい:基本機能
777
+
778
+ * 高速全文検索+ソート
779
+ * 検索キーワードハイライト
780
+ * キーワード周辺テキスト表示
781
+
782
+ = おさらい:高度な機能
783
+
784
+ * オートコンプリート
785
+ * ローマ字対応(seiki→正規表現)
786
+ * 類似マニュアル検索
787
+ * 同義語展開
788
+ * 「@」→「@ OR エラー制御演算子」
789
+
790
+ = 開発者募集!
791
+
792
+ * 公式検索システム置き換え!?
793
+ * 必要そう:複数バージョン対応
794
+ * 必要そう:複数言語対応
795
+ * マニュアルをさらによく!
796
+ * 検索を便利に!→ユーザー増加!
797
+ * →フィードバックする人も増加!
798
+
799
+ = 使いたい!
800
+
801
+ * WEICさんが運用予定!
802
+ * 2017年10月中にリリース予定
803
+ * URL: http://phpdocs.weic.co.jp/
804
+ * 宣伝(('note:(運用スポンサーの宣伝枠)'))
805
+ * PHPエンジニア大募集!
806
+ * 業務時間内にこれの開発もできる!?
807
+
808
+ = PHP document search情報
809
+
810
+ * ソース
811
+ * (('tag:x-small'))https://github.com/kou/php-document-search
812
+ * OSS
813
+ * MITライセンス
814
+
815
+ = まとめ
816
+
817
+ * PostgreSQL + PGroonga
818
+ * 高速日本語全文検索サービスを\n
819
+ ((*PHP*))で簡単に作れる!
820
+ * 開発者募集!
821
+ * サービス提供予定 by WEIC!
822
+ * URL: http://phpdocs.weic.co.jp/
823
+
824
+ = MySQLでもできる?
825
+
826
+ * MySQL・PostgreSQLだけで作る\n
827
+ 高速でリッチな\n
828
+ 全文検索システム
829
+ * db tech showcase Tokyo 2017の資料
830
+ * PGroongaの代わりにMroongaを使う
831
+ * SQLでの書き方だけでPHPの話はない
832
+
833
+ (('tag:center'))
834
+ (('tag:xx-small'))
835
+ https://slide.rabbit-shocker.org/authors/kou/db-tech-showcase-tokyo-2017/
836
+
837
+ = PHP+MySQL+Mroonga入門
838
+
839
+ * Groongaではじめる全文検索
840
+ * https://grnbook-ja.tumblr.com/
841
+ * 著者:北市真
842
+ * PHP+Mroonga入門の電子書籍
843
+ * 今はまだ無料!
844
+
845
+ = PHPの開発へ参加!
846
+
847
+ * PHPの開発に参加しませんか?
848
+ * 例:PDO/LaravelのPostgreSQL関連
849
+ * 例:マニュアル生成まわり
850
+ * 例:PHP document search関連
851
+ * (('wait'))やりたいけど自分はムリそう…
852
+ * そんなことはないんですよ!
853
+
854
+ = OSS Gate
855
+
856
+ * OSS Gate
857
+ * OSS開発者を増やす取り組み
858
+ * OSS Gateワークショップ
859
+ * OSS開発未経験者を経験者にする\n
860
+ ワークショップ
861
+ * PHPもOSS!
862
+
863
+ = ワークショップ
864
+
865
+ * このカンファレンス内で開催!
866
+ * 午後にこの部屋で開催(('note:(2時間45分)'))
867
+ * 参加希望者は私に声をかけて!
868
+ * PHP関連のOSSの開発に\n
869
+ 参加する人を増やそう!
870
+ * 今回だけで終わりにしないで\n
871
+ ((*今回を始まりにしたい!*))
data/theme.rb ADDED
@@ -0,0 +1,5 @@
1
+ @title_slide_title_font_size = @large_font_size
2
+
3
+ @groonga_product = "pgroonga"
4
+
5
+ include_theme("groonga")
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rabbit-slide-kou-php-conference-2017
3
+ version: !ruby/object:Gem::Version
4
+ version: 2017.10.08.0
5
+ platform: ruby
6
+ authors:
7
+ - Kouhei Sutou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rabbit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: rabbit-theme-groonga
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: |-
42
+ PHPマニュアルは日本語にも翻訳されていますが、検索機能が限定的なため、せっかくの説明を活用しきれません。基本の検索機能は関数やクラス名の検索機能しかないため「正規表現」で正規表現の使い方を検索できません。サイト内検索機能では「@」でエラー制御演算子を検索できません。
43
+
44
+ この講演ではPHPマニュアルをより活用するためのPHPマニュアル高速全文検索システムを紹介します。このシステムはPostgreSQLとPGroongaを利用して実現しています。
45
+ email:
46
+ - kou@clear-code.com
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".rabbit"
52
+ - README.rd
53
+ - Rakefile
54
+ - config.yaml
55
+ - images/php-document-search-search.png
56
+ - images/php-document-search-similar-search.png
57
+ - images/php-document-search-similar-search.xcf
58
+ - images/php-document-search-synonym.png
59
+ - images/php-document-search-synonym.xcf
60
+ - images/php-document-search.png
61
+ - images/php-manual-ja-full-text-search-by-at-not-found.png
62
+ - images/php-manual-ja-full-text-search-by-at-not-found.xcf
63
+ - images/php-manual-ja-full-text-search-link.png
64
+ - images/php-manual-ja-full-text-search-link.xcf
65
+ - images/php-manual-ja-search-by-at-not-found.png
66
+ - images/php-manual-ja-search-by-at-not-found.xcf
67
+ - images/php-manual-ja-search-by-at.png
68
+ - images/php-manual-ja-search-by-at.xcf
69
+ - images/php-manual-ja.png
70
+ - images/search-pg-bigm.pdf
71
+ - images/search-pgroonga-pg-bigm.pdf
72
+ - pdf/php-conference-2017-php-document-fast-full-text-search-system-with-postgresql-and-pgroonga.pdf
73
+ - php-document-fast-full-text-search-system-with-postgresql-and-pgroonga.rab
74
+ - theme.rb
75
+ homepage: http://slide.rabbit-shocker.org/authors/kou/php-conference-2017/
76
+ licenses:
77
+ - CC BY 3.0
78
+ - CC BY-SA 4.0
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.5.2
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム
100
+ test_files: []