actsasflinn-ruby-tokyotyrant 0.1.9 → 0.2.0

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