actsasflinn-ruby-tokyotyrant 0.1.9 → 0.2.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.
data/README.rdoc CHANGED
@@ -4,7 +4,7 @@ This is a c extension for Ruby to access TokyoTyrant databases. It currently su
4
4
 
5
5
  == Install
6
6
 
7
- # install tokyocabinet (1.4.29) and tokyotyrant (requires 1.1.31)
7
+ # install tokyocabinet (1.4.30) and tokyotyrant (requires 1.1.33)
8
8
  # after installing tc and tt on linux I had to /sbin/ldconfig (as root)
9
9
  gem sources -a http://gems.github.com
10
10
  sudo gem install actsasflinn-ruby-tokyotyrant
@@ -135,15 +135,32 @@ This is not in production but the initial benchmarks are very interesting. Resul
135
135
 
136
136
  # full-text search with all tokens in
137
137
  t.query{ |q| q.condition(:paragraph, :ftsand, 'logos word') }
138
- # => ["chapter:1:paragraph:12", "chapter:1:paragraph:14", "chapter:1:paragraph:17", "chapter:1:paragraph:19", "chapter:1:paragraph:24", "chapter:1:paragraph:27", "chapter:1:paragraph:43", "chapter:1:paragraph:53", "chapter:1:paragraph:62", "chapter:1:paragraph:89", "chapter:1:paragraph:90", "chapter:1:paragraph:94", "chapter:9:paragraph:5", "chapter:9:paragraph:35", "chapter:11:paragraph:3", "chapter:13:paragraph:2", "chapter:13:paragraph:94", "chapter:13:paragraph:121"]
138
+ # => ["chapter:1:paragraph:12", "chapter:1:paragraph:14", "chapter:1:paragraph:17", "chapter:1:paragraph:19", "chapter:1:paragraph:24", "chapter:1:paragraph:27", "chapter:1:paragraph:43", "chapter:1:paragraph:53", "... lots more ..."]
139
139
 
140
140
  # full-text search with at least one token in
141
141
  t.query{ |q| q.condition(:paragraph, :ftsor, 'sermon key') }
142
- # => ["chapter:5:paragraph:1", "chapter:9:paragraph:3", "chapter:10:paragraph:1", "chapter:10:paragraph:4", "chapter:10:paragraph:28", "chapter:11:paragraph:3", "chapter:11:paragraph:66", "chapter:11:paragraph:69", "chapter:13:paragraph:4", "chapter:13:paragraph:5", "chapter:13:paragraph:69"]
142
+ # => ["chapter:5:paragraph:1", "chapter:9:paragraph:3", "chapter:10:paragraph:1", "chapter:10:paragraph:4", "chapter:10:paragraph:28", "chapter:11:paragraph:3", "chapter:11:paragraph:66", "chapter:11:paragraph:69", "... lots more ..."]
143
143
 
144
144
  # negated full-text search with at least one token in
145
145
  t.query{ |q| q.condition(:paragraph, '!ftsor', 'the god he and I that said') }
146
- # => ["chapter:1:paragraph:95", "chapter:1:paragraph:96", "chapter:1:paragraph:97", "chapter:1:paragraph:98", "chapter:1:paragraph:99", "chapter:2:paragraph:3", "chapter:2:paragraph:5", "chapter:2:paragraph:6", "chapter:2:paragraph:7", "chapter:2:paragraph:9", "chapter:2:paragraph:11", "chapter:2:paragraph:13", "chapter:2:paragraph:15", "chapter:2:paragraph:17", "chapter:2:paragraph:19", "chapter:2:paragraph:21", "chapter:2:paragraph:36", "chapter:2:paragraph:43", "chapter:2:paragraph:47", "chapter:2:paragraph:48", "chapter:2:paragraph:49", "chapter:5:paragraph:4", "chapter:10:paragraph:27", "chapter:10:paragraph:62", "chapter:10:paragraph:64", "chapter:13:paragraph:3", "chapter:13:paragraph:9", "chapter:13:paragraph:17", "chapter:13:paragraph:24", "chapter:13:paragraph:29", "chapter:13:paragraph:32", "chapter:13:paragraph:37", "chapter:13:paragraph:45", "chapter:13:paragraph:50", "chapter:13:paragraph:56", "chapter:13:paragraph:59", "chapter:13:paragraph:63", "chapter:13:paragraph:67", "chapter:13:paragraph:70", "chapter:13:paragraph:76", "chapter:13:paragraph:82", "chapter:13:paragraph:87", "chapter:13:paragraph:88", "chapter:13:paragraph:90", "chapter:13:paragraph:98", "chapter:13:paragraph:101", "chapter:13:paragraph:105", "chapter:13:paragraph:110", "chapter:13:paragraph:113", "chapter:13:paragraph:117", "chapter:13:paragraph:123"]
146
+ # => ["chapter:1:paragraph:95", "chapter:1:paragraph:96", "chapter:1:paragraph:97", "chapter:1:paragraph:98", "chapter:1:paragraph:99", "chapter:2:paragraph:3", "chapter:2:paragraph:5", "chapter:2:paragraph:6", "... lots more ..."]
147
+
148
+ ==== Meta Search (Multi Query)
149
+
150
+ query1 = t.prepare_query{ |q| q.condition(:paragraph, :fts, 'rebirth') }
151
+ query2 = t.prepare_query{ |q| q.condition(:paragraph, :fts, 'logos') }
152
+
153
+ # Get the union of two query sets (OR)
154
+ t.search(:union, query1, query2)
155
+ # => ["chapter:13:paragraph:4", "chapter:13:paragraph:5", "chapter:13:paragraph:7", "chapter:13:paragraph:19", "chapter:13:paragraph:27", "chapter:13:paragraph:44", "chapter:13:paragraph:57", "... lots more ..."]
156
+
157
+ # Get the intersection of two query sets (AND)
158
+ t.search(:intersection, query1, query2)
159
+ # => ["chapter:13:paragraph:5", "chapter:13:paragraph:44", "chapter:13:paragraph:69"]
160
+
161
+ # Get the difference of two query sets (ANDNOT)
162
+ t.search(:diff, query1, query2)
163
+ # => ["chapter:13:paragraph:4", "chapter:13:paragraph:7", "chapter:13:paragraph:19", "chapter:13:paragraph:27", "chapter:13:paragraph:57", "chapter:13:paragraph:125"]
147
164
 
148
165
  === Lua Extension
149
166
 
@@ -159,3 +176,4 @@ This is not in production but the initial benchmarks are very interesting. Resul
159
176
  * Flinn Mueller (actsasflinn) author/maintainer
160
177
  * Justin Reagor (cheapRoc) specs
161
178
  * Seth Yates (sethyates) run method (lua ext)
179
+ * John Mettraux (jmettraux) inspiration (rufus-tokyo)
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ CLEAN.include('pkg', 'tmp')
20
20
 
21
21
  gemspec = Gem::Specification.new do |s|
22
22
  s.name = 'ruby-tokyotyrant'
23
- s.version = '0.1.9'
23
+ s.version = '0.2.0'
24
24
  s.authors = [ 'Flinn' ]
25
25
  s.email = 'flinn@actsasflinn.com'
26
26
  s.homepage = 'http://github.com/actsasflinn/ruby-tokyotyrant/'
@@ -143,6 +143,14 @@ static VALUE cQuery_set_pkey(VALUE vself, VALUE vpkey) {
143
143
  return rb_iv_set(vself, "@pkey", vpkey);
144
144
  }
145
145
 
146
+ static VALUE cQuery_hint(VALUE vself){
147
+ VALUE vqry;
148
+ RDBQRY *qry;
149
+ vqry = rb_iv_get(vself, RDBQRYVNDATA);
150
+ Data_Get_Struct(vqry, RDBQRY, qry);
151
+ return rb_str_new2(tcrdbqryhint(qry));
152
+ }
153
+
146
154
  void init_query(){
147
155
  rb_define_const(cQuery, "CSTREQ", INT2NUM(RDBQCSTREQ));
148
156
  rb_define_const(cQuery, "CSTRINC", INT2NUM(RDBQCSTRINC));
@@ -185,4 +193,5 @@ void init_query(){
185
193
  rb_define_method(cQuery, "get", cQuery_get, 0);
186
194
  rb_define_method(cQuery, "set_pkey", cQuery_set_pkey, 1);
187
195
  rb_define_alias(cQuery, "pkey=", "set_pkey");
196
+ rb_define_method(cQuery, "hint", cQuery_hint, 0);
188
197
  }
@@ -267,6 +267,48 @@ static VALUE cTable_find(VALUE vself){
267
267
  return vary;
268
268
  }
269
269
 
270
+ static VALUE cTable_search(int argc, VALUE *argv, VALUE vself){
271
+ VALUE vqrys, vkeys, vtype, vhash, vcols;
272
+ TCMAP *recs, *cols;
273
+ int qsiz, type, j;
274
+ const char *kbuf;
275
+ int ksiz, vsiz;
276
+ TCRDB *db = mTokyoTyrant_getdb(vself);
277
+
278
+ // rb_scan_args(argc, argv, "*", &vargs);
279
+ rb_scan_args(argc, argv, "1*", &vtype, &vqrys);
280
+
281
+ // vtype = rb_ary_pop(vargs);
282
+ qsiz = argc - 1;
283
+ RDBQRY *qrys[qsiz];
284
+
285
+ vtype = StringValueEx(vtype);
286
+ type = tctdbstrtometasearcytype(RSTRING_PTR(vtype));
287
+
288
+ for(j = 0; j < qsiz; j++){
289
+ VALUE vqry = rb_iv_get(rb_ary_entry(vqrys, j), RDBQRYVNDATA);
290
+ Data_Get_Struct(vqry, RDBQRY, qrys[j]);
291
+ }
292
+ TCLIST *res = tcrdbmetasearch(qrys, qsiz, type);
293
+ vkeys = listtovary(res);
294
+ tclistdel(res);
295
+
296
+ recs = varytomap(vkeys);
297
+ if(!tcrdbget3(db, recs)) return Qnil;
298
+ vhash = rb_hash_new();
299
+ tcmapiterinit(recs);
300
+ while((kbuf = tcmapiternext(recs, &ksiz)) != NULL){
301
+ const char *vbuf = tcmapiterval(kbuf, &vsiz);
302
+ cols = tcstrsplit4(vbuf, vsiz);
303
+ vcols = maptovhash(cols);
304
+ tcmapdel(cols);
305
+ rb_hash_aset(vhash, StringRaw(kbuf, ksiz), vcols);
306
+ }
307
+ tcmapdel(recs);
308
+
309
+ return vkeys;
310
+ }
311
+
270
312
  void init_table(){
271
313
  rb_define_method(cTable, "mput", cTable_mput, 1);
272
314
  rb_define_alias(cTable, "lput", "mput"); // Rufus Compat
@@ -291,4 +333,5 @@ void init_table(){
291
333
  rb_define_method(cTable, "prepare_query", cTable_prepare_query, 0);
292
334
  rb_define_method(cTable, "query", cTable_query, 0);
293
335
  rb_define_method(cTable, "find", cTable_find, 0);
336
+ rb_define_method(cTable, "search", cTable_search, -1);
294
337
  }
@@ -120,4 +120,14 @@ describe TokyoTyrant::Query, "with an open database" do
120
120
  {'type'=>"Cucumber", 'code'=>"4595", :pk=>"4595", 'variety'=>"Lemon"},
121
121
  {'type'=>"Cucumber", 'code'=>"4596", :pk=>"4596", 'variety'=>"Pickling / Gherkin"}]
122
122
  end
123
+
124
+ it "should return a query hint" do
125
+ @db.set_index(:type, :lexical)
126
+ q = @db.query
127
+ q.condition(:type, :streq, 'Cucumber')
128
+ q.order_by(:code)
129
+ q.limit(3)
130
+ q.run
131
+ q.hint.should == "\nusing an index: \"type\" asc (STREQ)\nresult set size: 5\nsorting the result set: \"code\"\n"
132
+ end
123
133
  end
@@ -267,4 +267,24 @@ describe TokyoTyrant::Table, "with an open database" do
267
267
  it "should run lua extensions" do
268
268
  @db.ext('echo', 'hello', 'world').should == "hello\tworld"
269
269
  end
270
+
271
+ it "should perform meta search with multiple query objects" do
272
+ keys = %w[falafel humus couscous tabbouleh tzatziki peanutbutter]
273
+ values = [{ 'ingredient' => 'chickpeas' },
274
+ { 'ingredient' => 'chickpeas' },
275
+ { 'ingredient' => 'semolina' },
276
+ { 'ingredient' => 'bulgar' },
277
+ { 'ingredient' => 'yogurt' },
278
+ { 'ingredient' => 'peanuts'}]
279
+
280
+ keys.each_with_index{ |k,i| @db[k] = values[i] }
281
+
282
+ query1 = @db.prepare_query{ |q| q.condition('ingredient', :streq, 'yogurt').order_by('ingredient') }
283
+ query2 = @db.prepare_query{ |q| q.condition('ingredient', :streq, 'chickpeas').order_by('ingredient') }
284
+ query3 = @db.prepare_query{ |q| q.condition('ingredient', :ftsex, 'pea').order_by('ingredient') }
285
+
286
+ @db.search(:union, query1, query2).should == ["falafel", "humus", "tzatziki"]
287
+ @db.search(:diff, query1, query2).should == ["tzatziki"]
288
+ @db.search(:intersection, query2, query3).should == ["falafel", "humus"]
289
+ end
270
290
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actsasflinn-ruby-tokyotyrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flinn