rabbit-slide-kou-php-study-115 2017.6.28.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []