rabbit-slide-kou-php-study-115 2017.6.28.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f64302499b9552f46f45c23ee1f40dc8f373dde8
4
+ data.tar.gz: cf4f2dbfcc631c701060756b7a663548679550ac
5
+ SHA512:
6
+ metadata.gz: 6340703dee9b280e2adf2add8c6a96142e23301278891b48050f9fdc245c30dc21b3667eeb02c389279d139b04481cc584ca4d5dc7e641b26c1fcc0821b6f891
7
+ data.tar.gz: 3184045e48a1ef27da14ebc481e25033ff123397b80568ad7cd736069d6208da5e65276c9199f90ac8395189138623cb121f5aebecfc8787579b2dd28d01a15e
data/.rabbit ADDED
@@ -0,0 +1 @@
1
+ fast-japanese-full-text-search-with-php-and-postgresql-and-pgroonga.rab
@@ -0,0 +1,46 @@
1
+ = PHPでPostgreSQLとPGroongaを使って高速日本語全文検索!
2
+
3
+ PHPでPostgreSQLとPGroongaを使って高速日本語全文検索を実現する方法を紹介します!これを参考にLIKEよりも速くリッチな日本語全文検索機能を実現しましょう!
4
+
5
+ == ライセンス
6
+
7
+ === スライド
8
+
9
+ CC BY-SA 4.0
10
+
11
+ 原著作者名は以下の通りです。
12
+
13
+ * 須藤功平(またはKouhei Sutou)
14
+
15
+ === 画像
16
+
17
+ ==== Groonga・Mroonga・PGroongaのロゴ
18
+
19
+ CC BY 3.0
20
+
21
+ 原著作者名は以下の通りです。
22
+
23
+ * Groongaプロジェクト
24
+ * Mroongaプロジェクト
25
+ * PGroongaプロジェクト
26
+
27
+ == 作者向け
28
+
29
+ === 表示
30
+
31
+ rake
32
+
33
+ === 公開
34
+
35
+ rake publish
36
+
37
+ == 閲覧者向け
38
+
39
+ === インストール
40
+
41
+ gem install rabbit-slide-kou-fast-japanese-full-text-search-with-php-and-postgresql-and-pgroonga
42
+
43
+ === 表示
44
+
45
+ rabbit rabbit-slide-kou-fast-full-japanese-text-search-with-php-and-postgresql-and-pgroonga
46
+
@@ -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
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: php-study-115
3
+ base_name: fast-japanese-full-text-search-with-php-and-postgresql-and-pgroonga
4
+ tags:
5
+ - rabbit
6
+ - php
7
+ - postgresql
8
+ - full-text-search
9
+ - japanese
10
+ - pgroonga
11
+ - phpstudy
12
+ presentation_date: 2017-06-28
13
+ version: 2017.6.28.0
14
+ licenses:
15
+ - CC BY 3.0
16
+ - CC BY-SA 4.0
17
+ slideshare_id: phpstudy115
18
+ speaker_deck_id:
19
+ ustream_id:
20
+ vimeo_id:
21
+ youtube_id:
22
+ author:
23
+ markup_language: :rd
24
+ name: Kouhei Sutou
25
+ email: kou@clear-code.com
26
+ rubygems_user: kou
27
+ slideshare_user: kou
28
+ speaker_deck_user:
@@ -0,0 +1,502 @@
1
+ = PHPで\nPostgreSQLと\nPGroongaを使って\n高速日本語全文検索!
2
+
3
+ : author
4
+ 須藤功平
5
+ : institution
6
+ クリアコード
7
+ : content-source
8
+ 第115回 PHP勉強会@東京
9
+ : date
10
+ 2017-06-28
11
+ : allotted-time
12
+ 20m
13
+ : theme
14
+ .
15
+
16
+ = PostgreSQLと全文検索
17
+
18
+ * LIKE:組込機能
19
+ * textsearch:組込機能
20
+ * pg_trgm:標準添付
21
+ * アーカイブには含まれている
22
+ * 別途インストールすれば使える
23
+
24
+ = LIKE
25
+
26
+ * 少ないデータ
27
+ * 十分実用的
28
+ * 400文字×20万件くらいなら1秒とか
29
+ * 少なくないデータ
30
+ * 性能問題アリ
31
+
32
+ = textsearch
33
+
34
+ * インデックスを作るので速い
35
+ * 言語毎にモジュールが必要
36
+ * 英語やフランス語などは組込
37
+ * 日本語は別途必要
38
+ * 日本語用モジュール
39
+ * 公式にはメンテナンスされていない\n
40
+ (('note:forkして動くようにしている人はいる'))
41
+
42
+ = pg_trgm
43
+
44
+ * インデックスを作るので速い
45
+ * 注:ヒット件数が増えると遅い
46
+ * 注:テキスト量が多いと遅い
47
+ * 注:1,2文字の検索は遅い(('note:(米・日本)'))
48
+
49
+ * 日本語を使うにはひと工夫必要
50
+ * C.UTF-8を使う
51
+ * ソースを変更してビルド
52
+
53
+ = プラグイン
54
+
55
+ * pg_bigm
56
+ * pg_trgmの日本語対応強化版
57
+ * PGroonga
58
+ * 本気の全文検索エンジンを利用
59
+ * 速いし日本語もバッチリ!
60
+
61
+ = ベンチマーク:pg_bigm
62
+
63
+ # image
64
+ # src = images/search-pg-bigm.pdf
65
+ # relative_height = 100
66
+
67
+ = ベンチマーク:PGroonga
68
+
69
+ # image
70
+ # src = images/search-pgroonga-pg-bigm.pdf
71
+ # relative_height = 100
72
+
73
+ = よし!
74
+
75
+ * PostgreSQLとPGroongaを使って
76
+ * 高速日本語全文検索サービスを
77
+ * PHPで作ろう!
78
+
79
+ = PHP document search
80
+
81
+ # image
82
+ # src = images/php-document-search.png
83
+ # relative_height = 100
84
+
85
+ = 機能
86
+
87
+ * 検索キーワードハイライト
88
+ * キーワード周辺テキスト表示
89
+ * オートコンプリート
90
+ * ローマ字対応(seiki→正規表現)
91
+
92
+ = 作り方:ツール
93
+
94
+ * フレームワーク
95
+ * Laravel
96
+ * RDBMS
97
+ * PostgreSQL
98
+ * 高速日本語全文検索機能
99
+ * PGroonga
100
+
101
+ = 作り方:インストール
102
+
103
+ * Laravel
104
+ * 省略
105
+ * PostgreSQL
106
+ * パッケージで
107
+ * PGroonga
108
+ * パッケージで\n
109
+ (('tag:x-small:https://pgroonga.github.io/ja/install/'))
110
+
111
+ = 初期化:Laravel
112
+
113
+ # coderay console
114
+
115
+ % laravel new php-document-search
116
+ % cd php-document-search
117
+ % editor .env
118
+
119
+ = 初期化:データベース
120
+
121
+ # coderay console
122
+
123
+ % sudo -u postgres -H \
124
+ createdb php_document_search
125
+
126
+ = 初期化:PGroonga
127
+
128
+ # rouge sql
129
+ -- ↓を実行する必要がある
130
+ CREATE EXTENSION pgroonga;
131
+
132
+ = 初期化:PGroonga
133
+
134
+ (('tag:center'))
135
+ マイグレーションファイル作成
136
+
137
+ # coderay console
138
+
139
+ % php artisan \
140
+ make:migration enable_pgroonga
141
+
142
+ = マイグレーション
143
+
144
+ # coderay php
145
+
146
+ public function up()
147
+ {
148
+ DB::statement("CREATE EXTENSION pgroonga;");
149
+ }
150
+
151
+ public function down()
152
+ {
153
+ DB::statement("DROP EXTENSION pgroonga;");
154
+ }
155
+
156
+ = モデル作成
157
+
158
+ * ドキュメントはモデル
159
+ * 名前:((%Entry%))
160
+ * 1ページ1インスタンス
161
+
162
+ = モデル作成
163
+
164
+ # coderay console
165
+
166
+ % php artisan \
167
+ make:model \
168
+ --migration \
169
+ --controller \
170
+ --resource \
171
+ Entry
172
+
173
+ = マイグレーション
174
+
175
+ # coderay php
176
+
177
+ public function up() {
178
+ Schema::create('entries', function ($table) {
179
+ $table->increments('id');
180
+ table->text('url');
181
+ $table->text('title');
182
+ $table->text('content');
183
+ // PGroonga用インデックス。デフォルトで全文検索用。
184
+ // 主キー(id)も入れるのが大事!スコアー取得に必要。
185
+ $table->index(
186
+ ['id', 'title', 'content'], null, 'pgroonga');
187
+ });
188
+ }
189
+
190
+ = データ登録
191
+
192
+ (1) PHPのドキュメントを\n
193
+ ローカルで生成
194
+ * PHPのドキュメントの作り方\n
195
+ http://doc.php.net/tutorial/
196
+ * フィードバックチャンスがいろいろあったよ!(後述)
197
+ (2) ページ毎にPostgreSQLに挿入
198
+
199
+ = コマンド作成
200
+
201
+ # coderay console
202
+
203
+ % php artisan \
204
+ make:command \
205
+ --command=doc:register \
206
+ RegisterDocuments
207
+
208
+ = 登録コマンド実装(一部)
209
+
210
+ # coderay php
211
+
212
+ public function handle()
213
+ {
214
+ foreach (glob("public/doc/*.html") as $html_path) {
215
+ $document = new \DOMDocument();
216
+ @$document->loadHTMLFile($html_path);
217
+ $xpath = new \DOMXPath($document);
218
+ $entry = new Entry();
219
+ $entry->url = "/doc/" . basename($html_path);
220
+ // XPathでテキスト抽出
221
+ $this->extract_title($entry, $xpath);
222
+ $this->extract_content($entry, $xpath);
223
+ $entry->save();
224
+ }
225
+ }
226
+
227
+ = 登録
228
+
229
+ # coderay console
230
+
231
+ % php artisan doc:register
232
+
233
+ = 検索用コントローラー
234
+
235
+ # coderay php
236
+
237
+ public function index(Request $request)
238
+ {
239
+ $query = $request['query'];
240
+ $entries = Entry::query()
241
+ // ↓はモデルに作る(後述)
242
+ ->fullTextSearch($query)
243
+ ->limit(10)
244
+ ->get();
245
+ return view('entry.search.index',
246
+ [
247
+ 'entries' => $entries,
248
+ 'query' => $query,
249
+ ]);
250
+ }
251
+
252
+ = 検索対象モデル
253
+
254
+ # coderay php
255
+
256
+ public function
257
+ scopeFullTextSearch($query, $search_query)
258
+ {
259
+ if ($search_query) {
260
+ return ...; // クエリーがあったら検索
261
+ } else {
262
+ return ...; // なかったら適当に返す(省略)
263
+ }
264
+ }
265
+
266
+ = 検索対象モデル:検索
267
+
268
+ # coderay php
269
+
270
+ return $query
271
+ ->select('id', 'url')
272
+ // 適合度をスコアーとして返す
273
+ ->selectRaw('pgroonga.score(entries) AS score')
274
+ // キーワードハイライト
275
+ ->highlightHTML('title', $search_query)
276
+ // キーワード周辺のテキスト(キーワードハイライト付き)
277
+ ->snippetHTML('content', $search_query)
278
+ // タイトルと本文を全文検索(後で補足)
279
+ ->whereRaw('title @@ ? OR content @@ ?',
280
+ [$search_query, $search_query])
281
+ // それっぽい文書の順に返す
282
+ ->orderBy('score', 'DESC');
283
+
284
+ = キーワードハイライト
285
+
286
+ # coderay php
287
+
288
+ public function scopeHighlightHTML($query,
289
+ $column,
290
+ $search_query)
291
+ {
292
+ return $query
293
+ // PGroonga提供ハイライト関数
294
+ ->selectRaw("pgroonga.highlight_html($column, " .
295
+ // PGroonga提供クエリーからキーワードを抽出する関数
296
+ "pgroonga.query_extract_keywords(?)) " .
297
+ "AS highlighted_$column",
298
+ [$search_query]);
299
+ }
300
+
301
+ = 検索結果
302
+
303
+ # coderay php
304
+
305
+ <div class="entries">
306
+ @foreach ($entries as $entry)
307
+ <a href="{{ $entry->url }}">
308
+ <h4>
309
+ {{-- マークアップ済み! --}}
310
+ {!! $entry->highlighted_title !!}
311
+ <span class="score">{{ $entry->score }}</span>
312
+ </h4>
313
+ {{-- 周辺テキストはtext[](後で補足) --}}
314
+ @foreach ($entry->content_snippets as $snippet)
315
+ <pre class="snippet">{!! $snippet !!}</pre>
316
+ @endforeach
317
+ </a>
318
+ @endforeach
319
+ </div>
320
+
321
+ = 検索対象モデル:配列
322
+
323
+ # coderay php
324
+
325
+ public function getContentSnippetsAttribute($value)
326
+ { // PostgreSQLは配列をサポートしているがPDOは未サポート
327
+ // '["...","..."]'という文字列になるのでそれを配列に変換
328
+ return array_map(
329
+ function ($e) {
330
+ // 「"」が「\"」になっているので戻す
331
+ return preg_replace('/\\\\(.)/', '$1', $e);
332
+ },
333
+ explode('","', substr($value, 2, -2)));
334
+ }
335
+
336
+ = 高速日本語全文検索!
337
+
338
+ # image
339
+ # src = images/php-document-search-search.png
340
+ # relative_height = 100
341
+
342
+ = オートコンプリート
343
+
344
+ * 必要なもの
345
+ * 候補用テーブル
346
+ * 候補のヨミガナ(カタカナ)
347
+ * PGroonga!!!
348
+
349
+ = モデル作成
350
+
351
+ # coderay console
352
+
353
+ % php artisan \
354
+ make:model \
355
+ --migration \
356
+ --controller \
357
+ --resource \
358
+ Term
359
+
360
+ = マイグレーション:カラム
361
+
362
+ # coderay php
363
+
364
+ public function up()
365
+ {
366
+ Schema::create('terms', function ($table) {
367
+ $table->increments('id');
368
+ $table->text('term');
369
+ $table->text('label');
370
+ $table->text('reading'); // 本当は配列にしたい
371
+ $table->timestamps();
372
+ // インデックス定義(後述)
373
+ });
374
+ }
375
+
376
+ = マイグレーション\nインデックス
377
+
378
+ # coderay php
379
+
380
+ $table->index([
381
+ // 候補に対する前方一致検索用
382
+ DB::raw('term pgroonga.text_term_search_ops_v2'),
383
+ // ヨミガナに対する前方一致RK検索用
384
+ DB::raw('reading pgroonga.text_term_search_ops_v2'),
385
+ ], null, 'pgroonga');
386
+ // 候補に対する全文検索用(中間一致用)
387
+ $table->index([DB::raw('term')], null, 'pgroonga');
388
+
389
+ = 前方一致RK検索
390
+
391
+ * 日本語特化の前方一致検索
392
+ * ローマ字・ひらがな・カタカナで\n
393
+ カタカナを前方一致検索できる
394
+ * gy→ギュウニュウ
395
+ * ぎ→ギュウニュウ
396
+ * ギ→ギュウニュウ
397
+
398
+ = 候補モデル:検索
399
+
400
+ # coderay php
401
+
402
+ public function
403
+ scopeComplete($query, $search_query)
404
+ {
405
+ return $query
406
+ ->select("label")
407
+ ->highlightHTML('label', $search_query)
408
+ ->whereRaw("term &^ :query OR " . // 前方一致検索
409
+ "reading &^~ :query OR " . // 前方一致RK検索
410
+ "term @@ :query", // 全文検索
411
+ ["query" => $search_query])
412
+ ->orderBy("label")
413
+ ->limit(10);
414
+ }
415
+
416
+ = コントローラー
417
+
418
+ # coderay php
419
+
420
+ public function index(Request $request)
421
+ {
422
+ $query = $request["query"];
423
+ // モデルに実装した検索処理を呼び出し
424
+ $terms = Term::query()->complete($query);
425
+ $data = [];
426
+ foreach ($terms->get() as $term) {
427
+ $data[] = [
428
+ "value" => $term->label,
429
+ "label" => $term->highlighted_label,
430
+ ];
431
+ }
432
+ // JSONで候補を返す
433
+ return response()->json($data);
434
+ }
435
+
436
+ = UI
437
+
438
+ # coderay javascript
439
+
440
+ $('#query').autocomplete({
441
+ source: function(request, response) {
442
+ $.ajax({
443
+ url: "/terms/", // コントローラー呼び出し
444
+ dataType: "json",
445
+ data: {query: this.term},
446
+ success: response
447
+ });
448
+ }
449
+ }).autocomplete("instance")._renderItem = function(ul, item) {
450
+ return $("<li>")
451
+ .attr("data-value", item.value) // 候補には生データを使う
452
+ .append(item.label) // ハイライトしたデータを表示
453
+ .appendTo(ul);
454
+ };
455
+
456
+ = オートコンプリート!
457
+
458
+ # image
459
+ # src = images/php-document-search.png
460
+ # relative_height = 100
461
+
462
+ = まとめ
463
+
464
+ * PGroongaを使えば…
465
+ * 高速日本語全文検索サービスを…
466
+ * ((*PHP*))で簡単に作れる!
467
+ * PHP document searchのソース
468
+ * (('tag:x-small'))https://github.com/kou/php-document-search
469
+
470
+ = その他(1)
471
+
472
+ * だれかPHP document searchを\n
473
+ メンテナンスしませんか?
474
+ * 普通に便利じゃないかと!
475
+ * 複数バージョン対応とか
476
+ * 複数言語対応とか
477
+
478
+ = その他(2)
479
+
480
+ * PHPの開発に参加しませんか?
481
+ * PDOのPostgreSQL対応強化とか
482
+ * ドキュメントまわりとか
483
+ * (('wait'))やりたいけど自分はムリそう…
484
+ * そんなことはないんですよ!
485
+
486
+ = その他(3)
487
+
488
+ * OSS Gateワークショップ
489
+ * OSS開発未経験者を経験者にする\n
490
+ ワークショップ
491
+ * PHPもOSS!
492
+ * 次回は7月29日\n
493
+ (('tag:x-small:https://oss-gate.doorkeeper.jp/events/upcoming'))
494
+
495
+ = その他(4)
496
+
497
+ * PHPカンファレンス2017内で\n
498
+ OSS Gateワークショップ開催は\n
499
+ どうですか!?
500
+ * PHP関連のOSSの開発に参加する人が\n
501
+ 増えるとうれしい?
502
+ * うれしいならコラボできそう
Binary file
@@ -0,0 +1,3 @@
1
+ @title_slide_title_font_size = @large_font_size * 1.2
2
+
3
+ include_theme("groonga")
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rabbit-slide-kou-php-study-115
3
+ version: !ruby/object:Gem::Version
4
+ version: 2017.6.28.0
5
+ platform: ruby
6
+ authors:
7
+ - Kouhei Sutou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-28 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: PHPでPostgreSQLとPGroongaを使って高速日本語全文検索を実現する方法を紹介します!これを参考にLIKEよりも速くリッチな日本語全文検索機能を実現しましょう!
42
+ email:
43
+ - kou@clear-code.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".rabbit"
49
+ - README.rd
50
+ - Rakefile
51
+ - config.yaml
52
+ - fast-japanese-full-text-search-with-php-and-postgresql-and-pgroonga.rab
53
+ - images/php-document-search-search.png
54
+ - images/php-document-search.png
55
+ - images/search-pg-bigm.pdf
56
+ - images/search-pgroonga-pg-bigm.pdf
57
+ - pdf/php-study-115-fast-japanese-full-text-search-with-php-and-postgresql-and-pgroonga.pdf
58
+ - theme.rb
59
+ homepage: http://slide.rabbit-shocker.org/authors/kou/php-study-115/
60
+ licenses:
61
+ - CC BY 3.0
62
+ - CC BY-SA 4.0
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.5.2
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: PHPでPostgreSQLとPGroongaを使って高速日本語全文検索!
84
+ test_files: []