rroonga 1.2.0 → 1.2.1

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.
Files changed (159) hide show
  1. data/README.textile +71 -0
  2. data/Rakefile +213 -128
  3. data/TODO +0 -0
  4. data/example/bookmark.rb +12 -12
  5. data/ext/groonga/Makefile +233 -0
  6. data/ext/groonga/extconf.rb +1 -1
  7. data/ext/groonga/rb-grn-column.c +5 -5
  8. data/ext/groonga/rb-grn-index-column.c +31 -0
  9. data/ext/groonga/rb-grn-index-cursor.c +106 -0
  10. data/ext/groonga/rb-grn-logger.c +5 -5
  11. data/ext/groonga/rb-grn-object.c +48 -0
  12. data/ext/groonga/rb-grn-patricia-trie.c +1 -1
  13. data/ext/groonga/rb-grn-plugin.c +32 -0
  14. data/ext/groonga/rb-grn-posting.c +51 -0
  15. data/ext/groonga/rb-grn-table-cursor.c +6 -1
  16. data/ext/groonga/rb-grn-table.c +31 -13
  17. data/ext/groonga/rb-grn.h +21 -3
  18. data/ext/groonga/rb-groonga.c +3 -1
  19. data/lib/groonga.rb +1 -0
  20. data/lib/groonga/dumper.rb +25 -5
  21. data/lib/groonga/expression-builder.rb +2 -2
  22. data/lib/groonga/pagination.rb +99 -7
  23. data/lib/groonga/posting.rb +87 -0
  24. data/lib/groonga/record.rb +118 -11
  25. data/lib/groonga/schema.rb +18 -1
  26. data/test/groonga-test-utils.rb +1 -6
  27. data/test/run-test.rb +13 -28
  28. data/test/test-column.rb +4 -0
  29. data/test/test-database-dumper.rb +53 -10
  30. data/test/test-hash.rb +6 -6
  31. data/test/test-index-cursor.rb +93 -0
  32. data/test/test-plugin.rb +6 -0
  33. data/test/test-record.rb +162 -1
  34. data/test/test-schema-type.rb +6 -0
  35. data/test/test-schema.rb +17 -0
  36. data/test/test-table.rb +7 -2
  37. data/test/test-type.rb +9 -1
  38. metadata +135 -245
  39. data/AUTHORS +0 -5
  40. data/NEWS.ja.rdoc +0 -344
  41. data/NEWS.rdoc +0 -346
  42. data/README.ja.rdoc +0 -68
  43. data/README.rdoc +0 -68
  44. data/example/search/config.ru +0 -230
  45. data/example/search/public/css/groonga.css +0 -122
  46. data/ext/.gitignore +0 -2
  47. data/html/bar.svg +0 -153
  48. data/html/developer.html +0 -151
  49. data/html/developer.svg +0 -469
  50. data/html/download.svg +0 -253
  51. data/html/favicon.ico +0 -0
  52. data/html/favicon.svg +0 -591
  53. data/html/footer.html.erb +0 -33
  54. data/html/head.html.erb +0 -4
  55. data/html/header.html.erb +0 -17
  56. data/html/heading-mark.svg +0 -393
  57. data/html/index.html +0 -243
  58. data/html/install.svg +0 -636
  59. data/html/logo.svg +0 -612
  60. data/html/ranguba.css +0 -342
  61. data/html/readme.svg +0 -256
  62. data/html/tutorial.svg +0 -559
  63. data/license/LGPL +0 -504
  64. data/test-unit-notify/Rakefile +0 -47
  65. data/test-unit-notify/lib/test/unit/notify.rb +0 -104
  66. data/test-unit/COPYING +0 -56
  67. data/test-unit/GPL +0 -340
  68. data/test-unit/PSFL +0 -271
  69. data/test-unit/Rakefile +0 -53
  70. data/test-unit/TODO +0 -5
  71. data/test-unit/bin/testrb +0 -5
  72. data/test-unit/html/bar.svg +0 -153
  73. data/test-unit/html/developer.svg +0 -469
  74. data/test-unit/html/favicon.ico +0 -0
  75. data/test-unit/html/favicon.svg +0 -82
  76. data/test-unit/html/heading-mark.svg +0 -393
  77. data/test-unit/html/index.html +0 -247
  78. data/test-unit/html/index.html.ja +0 -270
  79. data/test-unit/html/install.svg +0 -636
  80. data/test-unit/html/logo.svg +0 -483
  81. data/test-unit/html/test-unit.css +0 -339
  82. data/test-unit/html/tutorial.svg +0 -559
  83. data/test-unit/lib/test/unit.rb +0 -328
  84. data/test-unit/lib/test/unit/assertionfailederror.rb +0 -25
  85. data/test-unit/lib/test/unit/assertions.rb +0 -1334
  86. data/test-unit/lib/test/unit/attribute.rb +0 -125
  87. data/test-unit/lib/test/unit/autorunner.rb +0 -363
  88. data/test-unit/lib/test/unit/collector.rb +0 -36
  89. data/test-unit/lib/test/unit/collector/descendant.rb +0 -23
  90. data/test-unit/lib/test/unit/collector/dir.rb +0 -108
  91. data/test-unit/lib/test/unit/collector/load.rb +0 -144
  92. data/test-unit/lib/test/unit/collector/objectspace.rb +0 -34
  93. data/test-unit/lib/test/unit/color-scheme.rb +0 -106
  94. data/test-unit/lib/test/unit/color.rb +0 -96
  95. data/test-unit/lib/test/unit/diff.rb +0 -740
  96. data/test-unit/lib/test/unit/error.rb +0 -130
  97. data/test-unit/lib/test/unit/exceptionhandler.rb +0 -39
  98. data/test-unit/lib/test/unit/failure.rb +0 -136
  99. data/test-unit/lib/test/unit/fixture.rb +0 -176
  100. data/test-unit/lib/test/unit/notification.rb +0 -129
  101. data/test-unit/lib/test/unit/omission.rb +0 -191
  102. data/test-unit/lib/test/unit/pending.rb +0 -150
  103. data/test-unit/lib/test/unit/priority.rb +0 -180
  104. data/test-unit/lib/test/unit/runner/console.rb +0 -52
  105. data/test-unit/lib/test/unit/runner/emacs.rb +0 -8
  106. data/test-unit/lib/test/unit/runner/tap.rb +0 -8
  107. data/test-unit/lib/test/unit/testcase.rb +0 -483
  108. data/test-unit/lib/test/unit/testresult.rb +0 -121
  109. data/test-unit/lib/test/unit/testsuite.rb +0 -110
  110. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +0 -14
  111. data/test-unit/lib/test/unit/ui/console/testrunner.rb +0 -430
  112. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +0 -63
  113. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +0 -82
  114. data/test-unit/lib/test/unit/ui/testrunner.rb +0 -53
  115. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +0 -77
  116. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +0 -41
  117. data/test-unit/lib/test/unit/util/backtracefilter.rb +0 -42
  118. data/test-unit/lib/test/unit/util/method-owner-finder.rb +0 -28
  119. data/test-unit/lib/test/unit/util/observable.rb +0 -90
  120. data/test-unit/lib/test/unit/util/output.rb +0 -31
  121. data/test-unit/lib/test/unit/util/procwrapper.rb +0 -48
  122. data/test-unit/lib/test/unit/version.rb +0 -7
  123. data/test-unit/sample/adder.rb +0 -13
  124. data/test-unit/sample/subtracter.rb +0 -12
  125. data/test-unit/sample/test_adder.rb +0 -20
  126. data/test-unit/sample/test_subtracter.rb +0 -20
  127. data/test-unit/sample/test_user.rb +0 -23
  128. data/test-unit/test/collector/test-descendant.rb +0 -133
  129. data/test-unit/test/collector/test-load.rb +0 -442
  130. data/test-unit/test/collector/test_dir.rb +0 -406
  131. data/test-unit/test/collector/test_objectspace.rb +0 -100
  132. data/test-unit/test/run-test.rb +0 -15
  133. data/test-unit/test/test-attribute.rb +0 -86
  134. data/test-unit/test/test-color-scheme.rb +0 -69
  135. data/test-unit/test/test-color.rb +0 -47
  136. data/test-unit/test/test-diff.rb +0 -518
  137. data/test-unit/test/test-emacs-runner.rb +0 -60
  138. data/test-unit/test/test-fixture.rb +0 -287
  139. data/test-unit/test/test-notification.rb +0 -33
  140. data/test-unit/test/test-omission.rb +0 -81
  141. data/test-unit/test/test-pending.rb +0 -70
  142. data/test-unit/test/test-priority.rb +0 -119
  143. data/test-unit/test/test-testcase.rb +0 -544
  144. data/test-unit/test/test_assertions.rb +0 -1197
  145. data/test-unit/test/test_error.rb +0 -26
  146. data/test-unit/test/test_failure.rb +0 -33
  147. data/test-unit/test/test_testresult.rb +0 -113
  148. data/test-unit/test/test_testsuite.rb +0 -129
  149. data/test-unit/test/testunit-test-util.rb +0 -14
  150. data/test-unit/test/ui/test_tap.rb +0 -33
  151. data/test-unit/test/ui/test_testrunmediator.rb +0 -20
  152. data/test-unit/test/util/test-method-owner-finder.rb +0 -38
  153. data/test-unit/test/util/test-output.rb +0 -11
  154. data/test-unit/test/util/test_backtracefilter.rb +0 -41
  155. data/test-unit/test/util/test_observable.rb +0 -102
  156. data/test-unit/test/util/test_procwrapper.rb +0 -36
  157. data/test/.gitignore +0 -1
  158. data/text/expression.rdoc +0 -285
  159. data/text/tutorial.ja.rdoc +0 -433
@@ -1,102 +0,0 @@
1
- # Author:: Nathaniel Talbott.
2
- # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
3
- # License:: Ruby license.
4
-
5
- require 'test/unit/util/observable'
6
-
7
- module Test
8
- module Unit
9
- module Util
10
- class TC_Observable < TestCase
11
-
12
- class TF_Observable
13
- include Observable
14
- end
15
-
16
- def setup
17
- @observable = TF_Observable.new
18
- end
19
-
20
- def test_simple_observation
21
- assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do
22
- @observable.add_listener(:property, "a")
23
- end
24
-
25
- heard = false
26
- callback = proc { heard = true }
27
- assert_equal("a", @observable.add_listener(:property, "a", &callback), "add_listener should return the listener that was added")
28
-
29
- count = 0
30
- @observable.instance_eval do
31
- count = notify_listeners(:property)
32
- end
33
- assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified")
34
- assert(heard, "Should have heard the property changed")
35
-
36
- heard = false
37
- assert_equal(callback, @observable.remove_listener(:property, "a"), "remove_listener should return the callback")
38
-
39
- count = 1
40
- @observable.instance_eval do
41
- count = notify_listeners(:property)
42
- end
43
- assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified")
44
- assert(!heard, "Should not have heard the property change")
45
- end
46
-
47
- def test_value_observation
48
- value = nil
49
- @observable.add_listener(:property, "a") do |passed_value|
50
- value = passed_value
51
- end
52
- count = 0
53
- @observable.instance_eval do
54
- count = notify_listeners(:property, "stuff")
55
- end
56
- assert_equal(1, count, "Should have update the correct number of listeners")
57
- assert_equal("stuff", value, "Should have received the value as an argument to the listener")
58
- end
59
-
60
- def test_multiple_value_observation
61
- values = []
62
- @observable.add_listener(:property, "a") do |first_value, second_value|
63
- values = [first_value, second_value]
64
- end
65
- count = 0
66
- @observable.instance_eval do
67
- count = notify_listeners(:property, "stuff", "more stuff")
68
- end
69
- assert_equal(1, count, "Should have update the correct number of listeners")
70
- assert_equal(["stuff", "more stuff"], values, "Should have received the value as an argument to the listener")
71
- end
72
-
73
- def test_add_remove_with_default_listener
74
- assert_raises(ArgumentError, "add_listener should throw an exception if no callback is supplied") do
75
- @observable.add_listener(:property)
76
- end
77
-
78
- heard = false
79
- callback = proc { heard = true }
80
- assert_equal(callback, @observable.add_listener(:property, &callback), "add_listener should return the listener that was added")
81
-
82
- count = 0
83
- @observable.instance_eval do
84
- count = notify_listeners(:property)
85
- end
86
- assert_equal(1, count, "notify_listeners should have returned the number of listeners that were notified")
87
- assert(heard, "Should have heard the property changed")
88
-
89
- heard = false
90
- assert_equal(callback, @observable.remove_listener(:property, callback), "remove_listener should return the callback")
91
-
92
- count = 1
93
- @observable.instance_eval do
94
- count = notify_listeners(:property)
95
- end
96
- assert_equal(0, count, "notify_listeners should have returned the number of listeners that were notified")
97
- assert(!heard, "Should not have heard the property change")
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,36 +0,0 @@
1
- # Author:: Nathaniel Talbott.
2
- # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
3
- # License:: Ruby license.
4
-
5
- require 'test/unit'
6
- require 'test/unit/util/procwrapper'
7
-
8
- module Test
9
- module Unit
10
- module Util
11
- class TC_ProcWrapper < TestCase
12
- def munge_proc(&a_proc)
13
- return a_proc
14
- end
15
- def setup
16
- @original = proc {}
17
- @munged = munge_proc(&@original)
18
- @wrapped_original = ProcWrapper.new(@original)
19
- @wrapped_munged = ProcWrapper.new(@munged)
20
- end
21
- def test_wrapping
22
- assert_same(@original, @wrapped_original.to_proc, "The wrapper should return what was wrapped")
23
- end
24
- def test_hashing
25
-
26
- assert_equal(@wrapped_original.hash, @wrapped_munged.hash, "The original and munged should have the same hash when wrapped")
27
- assert_equal(@wrapped_original, @wrapped_munged, "The wrappers should be equivalent")
28
-
29
- a_hash = {@wrapped_original => @original}
30
- assert(a_hash[@wrapped_original], "Should be able to access the wrapper in the hash")
31
- assert_equal(a_hash[@wrapped_original], @original, "Should be able to access the wrapper in the hash")
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1 +0,0 @@
1
- /.test-result
@@ -1,285 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- = grn式 (grn_expr)
4
-
5
-
6
- == 名前
7
-
8
- grn式 - 検索条件やデータベースへの操作を表現する文字列の形式。(読み方:"ぐるんしき")
9
-
10
-
11
- == 書式
12
-
13
- grn式はquery形式とscript形式のいずれかによって表現することができます。
14
-
15
- query形式
16
-
17
- [条件式]
18
- 以下の条件式が使用できます。
19
-
20
- [文字列]
21
- 全文検索条件(デフォルト検索対象カラムの値が指定された文字列を含んでいる)
22
-
23
- ["文字列"]
24
- フレーズ検索条件(デフォルト検索対象カラムの値が指定されたフレーズを含んでいる)
25
-
26
- [カラム名:値]
27
- 一致条件(カラム値 == 値)
28
-
29
- [カラム名:!値]
30
- 不一致条件(カラム値 != 値)
31
-
32
- [カラム名:<値]
33
- 比較条件(カラム値 < 値)
34
-
35
- [カラム名:>値]
36
- 比較条件(カラム値 > 値)
37
-
38
- [カラム名:<=値]
39
- 比較条件(カラム値 <= 値)
40
-
41
- [カラム名:>=値]
42
- 比較条件(カラム値 >= 値)
43
-
44
- [カラム名:@文字列]
45
- 全文検索条件(カラム値が指定された文字列を含んでいる)
46
-
47
- [補助演算子 [1]]
48
- 全文検索条件の挙動を制御する以下の演算子が指定できます。
49
-
50
- [~文字列]
51
- 文字列を含んでいた場合は、そのレコードのスコアを下げます。
52
-
53
- [<文字列]
54
- 文字列を含んでいた場合に加算されるスコアの値を小さくします。
55
-
56
- [>文字列]
57
- 文字列を含んでいた場合に加算されるスコアの値を大きくします。
58
-
59
- [文字列*]
60
- 文字列に前方一致する条件を示します。
61
-
62
- [*S[数値]"文字列"]
63
- 文字列と関連する文書を検索します。文字列から抽出する特徴語の数を数値に指定します。
64
-
65
- [*N[数値]"文字列"]
66
- 文字列に含まれる複数の語が、近傍に含まれる文書を検索します。近傍の範囲の上限とな
67
- る語数を数値に指定します。N-gramの場合は、文字数を指定します。
68
-
69
- [結合演算子]
70
- 複数の条件式を結合するために以下の演算子が使用できる。演算子を伴わずに複数の条件式 が空白('
71
- ')区切りで指定された場合は、デフォルトの結合演算子が指定されたものとみな される。
72
-
73
- [a OR b]
74
- 論理和(aとbといずれかの条件がマッチする)
75
-
76
- [a + b]
77
- 論理積(aとbの両方がマッチする)
78
-
79
- [a - b]
80
- aにマッチし、bにはマッチしない
81
-
82
- [( )]
83
- 複数の条件をまとめる
84
-
85
- [プラグマ [2]]
86
- query形式文字列の先頭に、処理方法を指定するプラグマを埋め込むことができます。
87
-
88
- プラグマは必ずクエリ文字列の冒頭に存在しなければなりません。(先頭に空白を入れては いけません)
89
-
90
- 一つのクエリに複数のプラグマを指定することができます。
91
-
92
- 複数のプラグマを指定する場合は、間に空白を入れてはいけません。
93
-
94
- [*E数値1[,数値2]]
95
- 検索結果の数が数値1よりも小さい場合、完全一致→非わかち書き→部分一致の順に自動
96
- 的に検索処理方法を切り替えます。完全一致でヒットした文書と比べて非わかち書き一致、
97
- 部分一致でヒットした文書には数値2分だけ小さいスコアを付与します。数値2を省略した
98
- 場合は既定値(=2)と解釈されます。数値1に負の数を指定した場合は以下のように処理し ます。
99
-
100
- -1
101
-
102
- 完全一致検索のみを行う
103
-
104
- -2
105
-
106
- 非わかち書き検索のみを行う
107
-
108
- -3
109
-
110
- 完全一致検索と非わかち書き検索のみを行う
111
-
112
- -4
113
-
114
- 部分一致検索のみを行う
115
-
116
- -5
117
-
118
- 完全一致検索と部分一致検索のみを行う
119
-
120
- -6
121
-
122
- 非わかち書き検索と部分一致検索のみを行う
123
-
124
- -7
125
-
126
- 完全一致検索,非わかち書き検索,部分一致検索の全てを行う
127
-
128
- 例:
129
-
130
- *E10,3
131
-
132
- 検索結果数が10件以下だった場合に検索処理方法を順次切り替え、スコアを3ずつ小さ くします。
133
-
134
- [*D演算子]
135
- 結合演算子の既定値(演算子を省略した場合にどの演算を行うか)を指定します。指定できる演 算子は、OR, +, - のいずれかです。
136
-
137
- 例1:
138
-
139
- *D+ abc def
140
-
141
- abcとdefを両方含む文書を検索します。
142
-
143
- 例2:
144
-
145
- *DOR abc def
146
-
147
- abcとdefのいずれかを含む文書を検索します。
148
-
149
- [*W[数値[:重み][,数値[:重み]]...]
150
- 数値で指定されたセクション番号のみを対象に検索します。セクションごとに検索スコア
151
- の倍数を指定することができます。重みは、省略された場合1となります。負の重みも指 定することができます。
152
-
153
- script形式 [3]
154
-
155
- ECMAScript風の構文で検索条件やレコードへの操作を記述します。
156
-
157
- 式中のIDENTIFIER(識別子)は、以下のいずれかを指します。
158
-
159
- [引数名]
160
- grn式が受け取る引数の名前
161
-
162
- [カラム名]
163
- 操作対象としているレコードのカラム名
164
-
165
- [型名・関数名・テーブル名]
166
- データベースに定義された型・テーブル・関数の名前
167
-
168
-
169
- == 説明
170
-
171
- grn式は、検索条件やデータベースへの操作を表現するために使用される文字列の形式です。
172
-
173
- selectやloadなどのいくつかの組込コマンドや、API関数grn_table_select()などで使用されます。grn式はquery
174
- 形式とscript形式という2種類の方式で記述することができます。query形式は、多くのweb検索エンジンなどで検索フォームにユーザが指定
175
- 可能なクエリ文字列の書式に合わせた形式です。script形式は、ECMAScriptの構文から式(expression)以下の構文要素を抜粋
176
- した形式になっており、文(statement)や制御構造などは表現できません。
177
-
178
- query形式のgrn式もscript形式のgrn式も、共通の中間形式に翻訳された上で処理されますので、処理速度や効率には差違はありません。
179
- 記述できる処理の範囲はscript形式の方がquery形式より広くなっています。たとえば更新系の操作はscript形式のみで記述できます。
180
-
181
- DB-APIレイヤでは、異なる形式で記述された複数のgrn式を結合することも可能です。
182
-
183
-
184
- == 例
185
-
186
- query形式でcolumn1の値が'hoge'に等しいという条件
187
-
188
- column1:hoge
189
-
190
- script形式でcolumn1の値が'hoge'に等しいという条件
191
-
192
- column1 == "hoge"
193
-
194
-
195
- == 構文
196
-
197
- query形式のgrn式で有効な式の構文を拡張BNF記法で示します。
198
-
199
- query ::= query_element
200
- | ( query query_element )
201
- | ( query "+" query_element )
202
- | ( query "-" query_element )
203
- | ( query "OR" query_element )
204
- query_element ::= STRING
205
- | ( "(" query ")" )
206
- | ( IDENTIFIER relative_operator query_element )
207
- relative_operator ::= ( ":" | ":!" | ":<" | ":>" | ":<=" | ":>=" | ":@" )
208
-
209
- script形式のgrn式で有効な式の構文を拡張BNF記法で示します。
210
-
211
- expression ::= assignment_expression
212
- expression ::= ( expression "," assignment_expression )
213
- assignment_expression ::= conditional_expression
214
- | ( lefthand_side_expression assign_operator assignment_expression )
215
- assign_operator ::= ( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=" )
216
- conditional_expression ::= logical_or_expression
217
- | ( logical_or_expression "?" assignment_expression ":" assignment_expression )
218
- logical_or_expression ::= logical_and_expression
219
- | ( logical_or_expression "||" logical_and_expression )
220
- logical_and_expression ::= bitwise_or_expression
221
- | ( logical_and_expression logical_and_operator bitwise_or_expression )
222
- logical_and_operator ::= ( "&&" | "&!" )
223
- bitwise_or_expression ::= bitwise_xor_expression
224
- | ( bitwise_or_expression "|" bitwise_xor_expression )
225
- bitwise_xor_expression ::= bitwise_and_expression
226
- | ( bitwise_xor_expression "^" bitwise_and_expression )
227
- bitwise_and_expression ::= equality_expression
228
- | bitwise_and_expression "&" equality_expression )
229
- equality_expression ::= relational_expression
230
- | ( equality_expression equality_operator relational_expression )
231
- equality_operator ::= ( "==" | "!=" )
232
- relational_expression ::= shift_expression
233
- | ( relational_expression relational_operator shift_expression )
234
- relational_operator ::= ( "<" | ">" | "<=" | ">=" | "in" | "@" )
235
- shift_expression ::= additive_expression
236
- | ( shift_expression shift_operator additive_expression )
237
- shift_operator ::= ( "<<" | ">>" | ">>>" )
238
- additive_expression ::= multiplicative_expression
239
- | ( additive_expression additive_operator multiplicative_expression )
240
- additive_operator ::= ( "+" | "-" )
241
- multiplicative_expression ::= unary_expression
242
- | ( multiplicative_expression multiplicative_operator unary_expression )
243
- multiplicative_operator ::= ( "*" | "/" | "%" )
244
- unary_expression ::= postfix_expression
245
- | ( unary_operator unary_expression )
246
- unary_operator ::= ( "delete" : "++" : "--" : "+" : "-" : "!" : "~" )
247
- postfix_expression ::= lefthand_side_expression
248
- | ( lefthand_side_expression postfix_operator )
249
- postfix_operator ::= ( "++" | "--" )
250
- lefthand_side_expression ::= (call_expression | member_expression)
251
- call_expression ::= member_expression arguments
252
- member_expression ::= primary_expression
253
- member_expression ::= member_expression member_expression_part
254
- primary_expression ::= object_literal
255
- | ( "(" expression ")" )
256
- | IDENTIFIER
257
- | array_literal
258
- | DECIMAL
259
- | HEX_INTEGER
260
- | STRING
261
- | "true"
262
- | "false
263
- | "null"
264
- array_literal ::= ( "[" elision "]" )
265
- | ( "[" `element_list elision` "]" )
266
- | ( "[" element_list "]" )
267
- elision ::= "," | ( elision "," )
268
- element_list ::= assignment_expression
269
- | ( elision assignment_expression )
270
- | ( element_list elision assignment_expression )
271
- object_literal ::= ( "{" property_name_and_value_list "}" )
272
- property_name_and_value_list ::= ( property_name_and_value_list "," property_name_and_value )
273
- property_name_and_value ::= ( property_name ":" assignment_expression )
274
- property_name ::= IDENTIFIER | STRING | DECIMAL
275
- member_expression_part ::= "[" expression "]" | ( "." IDENTIFIER )
276
- arguments ::= ( "(" argument_list ")" )
277
- argument_list ::= assignment_expression | ( argument_list "," assignment_expression )
278
-
279
- -[ 脚注 ]-
280
-
281
- [1] 補助演算子はv1.0でサポートされます。
282
-
283
- [2] プラグマはv1.0でサポートされます。
284
-
285
- [3] script形式のgrn式はv1.0でサポートされます。
@@ -1,433 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- = チュートリアル
4
-
5
- このページでは簡単なアプリケーションの作成を通して
6
- rroongaの操作方法を紹介します。
7
-
8
- == インストール
9
-
10
- rroongaはRubyGemsでインストールできます。
11
-
12
- % sudo gem install rroonga
13
-
14
- == データベースの作成
15
-
16
- 簡単なブックマークアプリケーション用のデータベースを作ってみ
17
- ます。以下のようにgroongaライブラリを読み込んでirbを起動しま
18
- す。
19
-
20
- % irb --simple-prompt -rubygems -rgroonga
21
- >>
22
-
23
- まず、エンコーディングを設定します。ここではUTF-8を利用します。
24
-
25
- >> $KCODE = "UTF-8"
26
- => "UTF-8"
27
- >> Groonga::Context.default_options = {:encoding => :utf8}
28
- => {:encoding=>:utf8}
29
-
30
- それでは、ファイルを指定してデータベースを作成します。
31
-
32
- >> Groonga::Database.create(:path => "/tmp/bookmark.db")
33
- => #<Groonga::Database ...>
34
-
35
- ここで作成したデータベースは、これ以降、暗黙のうちに利用され
36
- ます。最初にデータベースを作成したら特に意識する必要はありま
37
- せん。
38
-
39
- == テーブルの定義
40
-
41
- groongaには以下の3種類のテーブルがあります。
42
-
43
- [Groonga::Hash]
44
- ハッシュテーブル。主キーでレコードを管理します。キーと完全
45
- 一致するレコードを非常に高速に検索することができます。
46
- [Groonga::PatriciaTrie]
47
- パトリシアトライ。ハッシュテーブルに比べて完全一致検索の速
48
- 度がやや遅いですが、前方一致検索・共通接頭辞探索などの検索
49
- が行えます。またカーソルを用いてキーの昇降順にレコードを取
50
- り出すことができます。
51
- [Groonga::Array]
52
- 配列。主キーの存在しないテーブルです。レコードはIDによって
53
- 識別します。
54
-
55
- ここではハッシュテーブルを利用して、<tt>Items</tt>という名前のテー
56
- ブルを作成します。キーは文字列とします。
57
-
58
- >> Groonga::Schema.create_table("Items", :type => :hash)
59
- => [...]
60
-
61
- これで<tt>Items</tt>という名前のテーブルが作成できました。
62
-
63
- 定義したテーブルはGroonga.[]で参照できます。
64
-
65
- >> items = Groonga["Items"]
66
- => #<Groonga::Hash ...>
67
-
68
- テーブルはRubyのHashのように扱えます。
69
-
70
- 例えば、以下のように+size+でテーブルに登録されているレコード
71
- の件数を取得できます。
72
-
73
- >> items.size
74
- => 0
75
-
76
- == レコードを追加する
77
-
78
- <tt>Items</tt>テーブルにレコードを追加します。
79
-
80
- >> items.add("http://ja.wikipedia.org/wiki/Ruby")
81
- => #<Groonga::Record ...>
82
- >> items.add("http://www.ruby-lang.org/ja/")
83
- => #<Groonga::Record ...>
84
-
85
- 件数を確認すると確かに2件増えています。
86
-
87
- >> items.size
88
- => 2
89
-
90
- 主キーを指定してレコードを取り出す時には以下のようにします。
91
-
92
- >> items["http://ja.wikipedia.org/wiki/Ruby"]
93
- => #<Groonga::Record ...>
94
-
95
- == 全文検索を行う
96
-
97
- 各itemのタイトル文字列を登録して、全文検索できるようにしてみ
98
- ましょう。
99
-
100
- まず<tt>Items</tt>テーブルに+title+という名前のカラムを追加し
101
- ます。ここでは、<tt>Text</tt>型のデータを持つカラムとして定義
102
- します。
103
-
104
- >> Groonga::Schema.change_table("Items") do |table|
105
- ?> table.text("title")
106
- >> end
107
- => [...]
108
-
109
- 定義したカラムは「#{テーブル名}.#{カラム名}」という名前になります。
110
- テーブルと同じようにGroonga.[]で参照できます。
111
-
112
- >> title_column = Groonga["Items.title"]
113
- => #<Groonga::VariableSizeColumn ...>
114
-
115
- 全文検索するために、文字列を分解して得られる各単語を格納する
116
- ためのテーブルを別途用意します。ここではTermsという名前でテー
117
- ブルを定義します。
118
-
119
- >> Groonga::Schema.create_table("Terms",
120
- ?> :type => :patricia_trie,
121
- ?> :key_normalize => true,
122
- ?> :default_tokenizer => "TokenBigram")
123
-
124
- ここでは、トークナイザとして<tt>:default_tokenzier =>
125
- "TokenBigram"</tt> を指定しています。トークナイザとは文字列を
126
- 単語に分解するオブジェクトのことです。デフォルトではトークナ
127
- イザは指定されていません。全文検索を利用するためにはトークナ
128
- イザを指定する必要があるので、ここではN-gramの一種であるバイ
129
- グラムを指定しています。
130
-
131
- N-gramを利用した全文検索では、分解したN文字とその出現位置を利
132
- 用して全文検索を行います。N-gramのNは文字列を何文字毎に分解す
133
- るかの文字数になります。groongaは1文字で分解するユニグラム、
134
- 2文字のバイグラム、3文字のトリグラムをサポートしています。
135
-
136
- また、大文字小文字の区別なく検索するために
137
- <tt>:key_normalize => true</tt>も指定しています。
138
-
139
- 単語格納用テーブルの準備ができたので、<tt>Items</tt>テーブ
140
- ルの+title+カラムに対するインデックスを定義します。
141
-
142
- >> Groonga::Schema.change_table("Terms") do |table|
143
- ?> table.index("Items.title")
144
- >> end
145
- => [...]
146
-
147
- 少し違和感を感じるかも知れませんが、<tt>Items</tt>テーブル
148
- のカラムに対するインデックスは、<tt>Terms</tt>テーブルのカ
149
- ラムとして定義します。
150
-
151
- <tt>Items</tt>にレコードが登録されると、その中に含まれる単
152
- 語に該当するレコードが<tt>Terms</tt>に自動的に追加されるよ
153
- うになります。
154
-
155
- <tt>Terms</tt>は、文書に含まれる語彙に相当する、やや特殊な
156
- テーブルだと言えます。しかし、他のテーブルと同様に語彙テーブ
157
- ルには自由にカラムを追加し、単語毎の様々な属性を管理すること
158
- ができます。これはある種の検索処理を行う際には非常に便利に機
159
- 能します。
160
-
161
- これでテーブルの定義は完了です。
162
-
163
- 先ほど登録した各レコードの+title+カラムに値をセットします。
164
-
165
- >> items["http://ja.wikipedia.org/wiki/Ruby"].title = "Ruby"
166
- => "Ruby"
167
- >> items["http://www.ruby-lang.org/ja/"].title = "オブジェクトスクリプト言語Ruby"
168
- "オブジェクトスクリプト言語Ruby"
169
-
170
- 以下のようにして検索することができます。
171
-
172
- >> ruby_items = items.select {|record| record.title =~ "Ruby"}
173
- => #<Groonga::Hash ..., size: <2>>
174
-
175
- 検索結果はGroonga::Hashで返されます。ハッシュのキーに見つかっ
176
- た<tt>Items</tt>のレコードが入っています。
177
-
178
- >> ruby_items.collect {|record| record.key.key}
179
- => ["http://ja.wikipedia.org/wiki/Ruby", "http://www.ruby-lang.org/ja/"]
180
-
181
- 上の例では+record.key+で<tt>Items</tt>のレコードを取得して、
182
- さらにそのキーを指定して(+record.key.key+)で<tt>Items</tt>
183
- のキーを返しています。
184
-
185
- +record["_key"]+でアクセスすると自動的に参照しているレコード
186
- を辿っていき、参照先のキーにアクセスできます。
187
-
188
- >> ruby_items.collect {|record| record["_key"]}
189
- => ["http://ja.wikipedia.org/wiki/Ruby", "http://www.ruby-lang.org/ja/"]
190
-
191
- == マルチユーザ向けのブックマークアプリケーション
192
-
193
- ここまでで作った単機能のアプリケーションをもう少し拡張して、
194
- 複数のユーザが、それぞれにコメントを記入できるブックマークア
195
- プリケーションにしてみましょう。
196
-
197
- まず、ユーザ情報とコメント情報を格納するテーブルを追加して、
198
- 下図のようなテーブル構成にします。
199
-
200
- http://qwik.jp/senna/senna2.files/rect4605.png
201
-
202
- まず、<tt>Users</tt>テーブルを追加します。
203
-
204
- >> Groonga::Schema.create_table("Users", :type => :hash) do |table|
205
- ?> table.text("name")
206
- >> end
207
- => [...]
208
-
209
- 次に、<tt>Comments</tt>テーブルを追加します。
210
-
211
- >> Groonga::Schema.create_table("Comments") do |table|
212
- ?> table.reference("item")
213
- >> table.reference("author", "Users")
214
- >> table.text("content")
215
- >> table.time("issued")
216
- >> end
217
- => [...]
218
-
219
- <tt>Comments</tt>テーブルの+content+カラムを全文検索できる
220
- ようにインデックスを定義します。
221
-
222
- >> Groonga::Schema.change_table("Terms") do |table|
223
- ?> table.index("Comments.content")
224
- >> end
225
- => [...]
226
-
227
- これでテーブルが定義できました。
228
-
229
- 続いてユーザを何人か追加します。
230
-
231
- >> users = Groonga["Users"]
232
- => #<Groonga::Hash ...>
233
- >> users.add("moritan", :name => "モリタン")
234
- => #<Groonga::Record ...>
235
- >> users.add("taporobo", :name => "タポロボ")
236
- => #<Groonga::Record ...>
237
-
238
- 次に、実際にユーザがブックマークを貼る時の処理を実行してみま
239
- しょう。
240
-
241
- ユーザ+moritan+が、Ruby関連のとあるページをブックマークしたと
242
- 想定します。
243
-
244
- まず対象のページが<tt>Items</tt>テーブルに登録済かどうか調
245
- べます。
246
-
247
- >> items.has_key?("http://www.rubyist.net/~matz/")
248
- => false
249
-
250
- 未登録なのでまず当該ページを<tt>Items</tt>に登録します。
251
-
252
- >> items.add("http://www.rubyist.net/~matz/",
253
- ?> :title => "Matzにっき")
254
- => #<Groonga::Record ...>
255
-
256
- 次に、登録したitemを+item+カラムの値に指定して
257
- <tt>Comments</tt>にレコードを登録します。
258
-
259
- >> require "time"
260
- => true
261
- >> comments = Groonga["Comments"]
262
- => #<Groonga::Array ...>
263
- >> comments.add(:item => "http://www.rubyist.net/~matz/",
264
- ?> :author => "moritan",
265
- ?> :content => "Ruby Matz",
266
- ?> :issued => Time.parse("2010-11-20T18:01:22+09:00"))
267
- => #<Groonga::Record ...>
268
-
269
- == メソッド化
270
-
271
- 上記の一連の手続きをメソッドにまとめてみます。
272
-
273
- >> @items = items
274
- => #<Groonga::Hash ...>
275
- >> @comments = comments
276
- => #<Groonga::Array ...>
277
- >> def add_bookmark(url, title, author, content, issued)
278
- >> item = @items[url] || @items.add(url, :title => title)
279
- >> @comments.add(:item => item,
280
- ?> :author => author,
281
- ?> :content => content,
282
- ?> :issued => issued)
283
- >> end
284
- => nil
285
-
286
- +itmes+と+comments+をインスタンス変数に代入しているのはメソッ
287
- ド内からでも見えるようにするためです。
288
-
289
- +add_bookmark+は以下のような手順を実行しています。
290
-
291
- * <tt>Items</tt>テーブルに該当ページのレコードがあるかどうか調べる。
292
- * レコードがなければ追加する。
293
- * <tt>Comments</tt>テーブルにレコードを登録する。
294
-
295
- 作成したメソッドを呼び出していくつかブックマークを登録してみ
296
- ましょう。
297
-
298
- >> add_bookmark("http://jp.rubyist.net/magazine/",
299
- ?> "Rubyist Magazine - るびま", "moritan", "Ruby 記事",
300
- ?> Time.parse("2010-10-07T14:18:28+09:00"))
301
- => #<Groonga::Record ...>
302
- >> add_bookmark("http://groonga.rubyforge.org/",
303
- ?> "Rubyでgroonga使って全文検索 - ラングバ", "taporobo",
304
- ?> "Ruby groonga 全文検索",
305
- ?> Time.parse("2010-11-11T12:39:59+09:00"))
306
- => #<Groonga::Record ...>
307
- >> add_bookmark("http://www.rubyist.net/~matz/",
308
- ?> "Matz日記", "taporobo", "Ruby 日記",
309
- ?> Time.parse("2010-07-28T20:46:23+09:00"))
310
- => #<Groonga::Record ...>
311
-
312
- == 全文検索その2
313
-
314
- 登録したレコードに対して全文検索を実行してみます。
315
-
316
- >> records = comments.select do |record|
317
- ?> record["content"] =~ "Ruby"
318
- >> end
319
- => #<Groonga::Hash ...>
320
- >> records.each do |record|
321
- ?> record = record.key
322
- >> p [record.id,
323
- ?> record.issued,
324
- ?> record.item.title,
325
- ?> record.author.name,
326
- ?> record.content]
327
- >> end
328
- [1, Sat Nov 20 18:01:22 +0900 2010, "Matzにっき", "モリタン", "Ruby Matz"]
329
- [2, Thu Oct 07 14:18:28 +0900 2010, "Rubyist Magazine - るびま", "モリタン", "Ruby 記事"]
330
- [3, Thu Nov 11 12:39:59 +0900 2010, "Rubyでgroonga使って全文検索 - ラングバ", "タポロボ", "Ruby groonga 全文検索検"]
331
- [4, Wed Jul 28 20:46:23 +0900 2010, "Matzにっき", "タポロボ", "Ruby 日記"]
332
-
333
- カラム名と同じメソッドでカラムへのアクセスできます。複合デー
334
- タ型の要素も再帰的に辿ることができます。(同様の出力を普通の
335
- RDBで実現するためには、<tt>Items</tt>テーブル、
336
- <tt>Comments</tt>テーブル、<tt>Users</tt>テーブルのJOIN操作が
337
- 必要になります。)
338
-
339
- 上の式の中で、肝心の検索処理は、第一引数の式を評価する時点で
340
- 完了していて、レコードセットオブジェクトとしてメモリに蓄積さ
341
- れています。
342
-
343
- >> records
344
- #<Groonga::Hash ..., size: <4>>
345
-
346
- レコードセットは、出力する前に様々に加工することができます。
347
-
348
- 以下は、日付で降順にソートしてから出力した例です。
349
-
350
- >> records.sort([{:key => "issued", :order => "descending"}]).each do |record|
351
- ?> record = record.key
352
- >> p [record.id,
353
- ?> record.issued,
354
- ?> record.item.title,
355
- ?> record.author.name,
356
- ?> record.content]
357
- >> end
358
- [1, Sat Nov 20 18:01:22 +0900 2010, "Matzにっき", "モリタン", "Ruby Matz"]
359
- [3, Thu Nov 11 12:39:59 +0900 2010, "Rubyでgroonga使って全文検索 - ラングバ", "タポロボ", "Ruby groonga 全文検索"]
360
- [2, Thu Oct 07 14:18:28 +0900 2010, "Rubyist Magazine - るびま", "モリタン", "Ruby 記事"]
361
- [4, Wed Jul 28 20:46:23 +0900 2010, "Matzにっき, "タポロボ", "Ruby 日記"]
362
- => [...]
363
-
364
- 同じitemが何度も出てくると検索結果が見にくいので、item毎にグ
365
- ループ化してみます。
366
-
367
- >> records.group("item").each do |record|
368
- ?> item = record.key
369
- >> p [record.n_sub_records,
370
- ?> item.key,
371
- ?> item.title]
372
- >> end
373
- [2, "http://www.rubyist.net/~matz/", "Matzにっき"]
374
- [1, "http://jp.rubyist.net/magazine/", "Rubyist Magazine - るびま"]
375
- [1, "http://groonga.rubyforge.org/", "Rubyでgroonga使って全文検索 - ラングバ"]
376
- => nil
377
-
378
- +n_sub_records+というのはグループ化した単位に含まれるレコード
379
- の件数を示します。SQLで言えば、GROUP BY句を含むクエリのcount
380
- 関数のような働きです。
381
-
382
- == 少し複雑な検索
383
-
384
- さらに実用的な検索について考えてみましょう。
385
-
386
- ブックマークが大量に蓄積されるに従って、より的確に適合度を算
387
- 出する必要性に迫られます。
388
-
389
- 今のところ検索対象として利用できるのは<tt>Items.title</tt>
390
- と<tt>Comments.content</tt>ですが、<tt>Items.title</tt>は
391
- 元ページから得られるやや信頼できる情報なのに対して、
392
- <tt>Comments.content</tt>はブックマークユーザが任意に設定で
393
- きる情報で、やや信憑性に乏しいと言えます。しかし、再現率を確
394
- 保するためにはユーザのコメントも是非対象に含めたいところです。
395
-
396
- そこで、以下のようなポリシーで検索を行うことにします。
397
-
398
- * <tt>Items.title</tt>か<tt>Comments.content</tt>のいずれ
399
- かにマッチするitemを検索する。
400
- * ただし、<tt>Items.title</tt>にマッチしたレコードはスコア
401
- を10倍重み付けする。
402
- * 同一のitemに対して、キーワードにマッチする<tt>comment</tt>
403
- が複数存在した場合は、それぞれの<tt>comment</tt>のスコアの
404
- 和を、該当するitemのスコアとする。
405
-
406
- 以下のようにして、commentとitemとそれぞれに対する検索結果を求
407
- めます。
408
-
409
- >> ruby_comments = @comments.select {|record| record.content =~ "Ruby"}
410
- => #<Groonga::Hash ..., size: <4>
411
- >> ruby_items = @items.select do |record|
412
- ?> target = record.match_target do |match_record|
413
- ?> match_record.title * 10
414
- >> end
415
- >> target =~ "Ruby"
416
- >> end
417
- #<Groonga::Hash ..., size: <4>>
418
-
419
- _ruby_comments_の結果をitem毎にグループ化し、_ruby_items_と
420
- unionして出力します。
421
-
422
- >> ruby_items = ruby_comments.group("item").union!(ruby_items)
423
- #<Groonga::Hash ..., size: <5>>
424
- >> ruby_items.sort([{:key => "_score", :order => "descending"}]).each do |record|
425
- >> p [record.score, record.title]
426
- >> end
427
- [10, "Rubyist Magazine - るびま"]
428
- [10, "Ruby"]
429
- [10, "Rubyでgroonga使って全文検索 - ラングバ"]
430
- [10, "オブジェクトスクリプト言語Ruby"]
431
- [2, "Matzにっき"]
432
-
433
- これで目的の結果が得られました。