rabbit-slide-kou-php-conference-2017 2017.10.08.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.
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: []