picky 4.12.8 → 4.12.10
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/picky/backends/redis/directly_manipulable.rb +1 -1
- data/lib/picky/backends/redis/list.rb +11 -10
- data/lib/picky/backends/redis.rb +3 -3
- data/lib/picky/backends/sqlite/basic.rb +11 -7
- data/lib/picky/bundle.rb +4 -0
- data/lib/picky/bundle_realtime.rb +11 -2
- data/spec/functional/realtime_spec.rb +224 -0
- data/spec/lib/backends/sqlite/array_spec.rb +4 -4
- data/spec/lib/backends/sqlite/value_spec.rb +2 -2
- data/spec/lib/bundle_indexed_spec.rb +3 -0
- metadata +4 -4
@@ -38,16 +38,14 @@ module Picky
|
|
38
38
|
def dump hash
|
39
39
|
unless @realtime
|
40
40
|
clear
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
client.zadd redis_key, i, value
|
48
|
-
end
|
41
|
+
hash.each_pair do |key, values|
|
42
|
+
redis_key = "#{namespace}:#{key}"
|
43
|
+
i = 0
|
44
|
+
values.each do |value|
|
45
|
+
i += 1
|
46
|
+
client.zadd redis_key, i, value
|
49
47
|
end
|
50
|
-
|
48
|
+
end
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
@@ -57,7 +55,9 @@ module Picky
|
|
57
55
|
#
|
58
56
|
def [] key
|
59
57
|
list = client.zrange "#{namespace}:#{key}", :'0', :'-1'
|
58
|
+
|
60
59
|
DirectlyManipulable.make self, list, key
|
60
|
+
|
61
61
|
list
|
62
62
|
end
|
63
63
|
|
@@ -72,8 +72,9 @@ module Picky
|
|
72
72
|
i += 1
|
73
73
|
client.zadd redis_key, i, value
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
DirectlyManipulable.make self, values, key
|
77
|
+
|
77
78
|
values
|
78
79
|
end
|
79
80
|
|
data/lib/picky/backends/redis.rb
CHANGED
@@ -61,7 +61,7 @@ module Picky
|
|
61
61
|
# [id] # => [:sym1, :sym2]
|
62
62
|
#
|
63
63
|
def create_realtime bundle
|
64
|
-
List.new client, "#{bundle.identifier}:realtime", realtime: realtime
|
64
|
+
List.new client, "#{PICKY_ENVIRONMENT}:#{bundle.identifier}:realtime", realtime: realtime
|
65
65
|
end
|
66
66
|
|
67
67
|
# Does the Redis version already include
|
@@ -137,7 +137,7 @@ module Picky
|
|
137
137
|
# else
|
138
138
|
# class << self
|
139
139
|
# def weight combinations
|
140
|
-
|
140
|
+
combinations.score
|
141
141
|
# end
|
142
142
|
# end
|
143
143
|
# end
|
@@ -217,7 +217,7 @@ module Picky
|
|
217
217
|
module Scripting
|
218
218
|
def ids combinations, amount, offset
|
219
219
|
identifiers = combinations.inject([]) do |identifiers, combination|
|
220
|
-
identifiers << "#{combination.identifier}"
|
220
|
+
identifiers << "#{PICKY_ENVIRONMENT}:#{combination.identifier}"
|
221
221
|
end
|
222
222
|
|
223
223
|
# Assume it's using EVALSHA.
|
@@ -18,11 +18,11 @@ module Picky
|
|
18
18
|
|
19
19
|
lazily_initialize_client
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
# Note: If on OSX, too many files get opened during
|
22
|
+
# the specs -> ulimit -n 3000
|
23
|
+
#
|
24
|
+
# rescue SQLite3::CantOpenException => e
|
25
|
+
#
|
26
26
|
end
|
27
27
|
|
28
28
|
def initial
|
@@ -45,9 +45,11 @@ module Picky
|
|
45
45
|
def clear
|
46
46
|
db.execute 'delete from key_value'
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
|
+
# TODO Replace with db method?
|
50
|
+
#
|
49
51
|
def lazily_initialize_client
|
50
|
-
@db ||= SQLite3::Database.new cache_path
|
52
|
+
@db ||= (create_directory cache_path; SQLite3::Database.new cache_path)
|
51
53
|
end
|
52
54
|
|
53
55
|
def dump_sqlite internal
|
@@ -65,6 +67,8 @@ module Picky
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def reset
|
70
|
+
# TODO Still necessary?
|
71
|
+
#
|
68
72
|
create_directory cache_path
|
69
73
|
lazily_initialize_client
|
70
74
|
|
data/lib/picky/bundle.rb
CHANGED
@@ -79,6 +79,8 @@ module Picky
|
|
79
79
|
|
80
80
|
# Extract specific indexes from backend.
|
81
81
|
#
|
82
|
+
# TODO Move @backend_ into the backend?
|
83
|
+
#
|
82
84
|
def create_backends
|
83
85
|
@backend_inverted = backend.create_inverted self
|
84
86
|
@backend_weights = backend.create_weights self
|
@@ -144,6 +146,8 @@ module Picky
|
|
144
146
|
|
145
147
|
# If a key format is set, use it, else forward to the category.
|
146
148
|
#
|
149
|
+
# TODO What about setting the key_format per category?
|
150
|
+
#
|
147
151
|
def key_format
|
148
152
|
@key_format || @category.key_format
|
149
153
|
end
|
@@ -1,7 +1,12 @@
|
|
1
1
|
module Picky
|
2
2
|
|
3
3
|
class Bundle
|
4
|
-
|
4
|
+
|
5
|
+
# TODO Push methods back into the backend, so that we
|
6
|
+
# can apply more efficient methods tailored for
|
7
|
+
# each specific backends.
|
8
|
+
#
|
9
|
+
|
5
10
|
# Removes the given id from the indexes.
|
6
11
|
#
|
7
12
|
def remove id
|
@@ -28,6 +33,9 @@ module Picky
|
|
28
33
|
@similarity.delete self.similarity_strategy.encode(str_or_sym)
|
29
34
|
else
|
30
35
|
@weights[str_or_sym] = self.weight_strategy.weight_for ids.size
|
36
|
+
# @weights[str_or_sym] = self.weight_strategy.respond_to?(:[]) &&
|
37
|
+
# self.weight_strategy[str_or_sym] ||
|
38
|
+
# self.weight_strategy.weight_for(ids.size)
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
@@ -37,6 +45,8 @@ module Picky
|
|
37
45
|
# Returns a reference to the array where the id has been added.
|
38
46
|
#
|
39
47
|
def add id, str_or_sym, where = :unshift
|
48
|
+
# Use a generalized strategy.
|
49
|
+
#
|
40
50
|
str_or_syms = @realtime[id] ||= []
|
41
51
|
|
42
52
|
# Inverted.
|
@@ -49,7 +59,6 @@ module Picky
|
|
49
59
|
# Update the realtime index.
|
50
60
|
#
|
51
61
|
str_or_syms << str_or_sym
|
52
|
-
|
53
62
|
ids = @inverted[str_or_sym] ||= []
|
54
63
|
ids.send where, id
|
55
64
|
end
|
@@ -473,5 +473,229 @@ describe "Realtime Indexing" do
|
|
473
473
|
end
|
474
474
|
end
|
475
475
|
end
|
476
|
+
|
477
|
+
context 'special index' do
|
478
|
+
let(:index) do
|
479
|
+
Picky::Index.new(:books) do
|
480
|
+
backend Picky::Backends::Redis.new(realtime: true)
|
481
|
+
key_format :to_s # TODO Make key format dependent on backend?
|
482
|
+
category :title
|
483
|
+
category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
let(:books) { Picky::Search.new index }
|
487
|
+
|
488
|
+
before(:each) do
|
489
|
+
index.add Book.new('one', 'Title', 'Author')
|
490
|
+
end
|
491
|
+
|
492
|
+
context 'single category updating' do
|
493
|
+
it 'finds the first entry' do
|
494
|
+
books.search('title:Titl').ids.should == ['one']
|
495
|
+
end
|
496
|
+
|
497
|
+
it 'allows removing a single category and leaving the others alone' do
|
498
|
+
index[:title].remove 'one'
|
499
|
+
|
500
|
+
books.search('Title').ids.should == []
|
501
|
+
books.search('Author').ids.should == ['one']
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'allows adding a single category and leaving the others alone' do
|
505
|
+
index[:title].add Book.new('two', 'Newtitle', 'Newauthor')
|
506
|
+
|
507
|
+
books.search('Title').ids.should == ['one']
|
508
|
+
books.search('Newtitle').ids.should == ['two']
|
509
|
+
|
510
|
+
books.search('Author').ids.should == ['one']
|
511
|
+
books.search('Newauthor').ids.should == []
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'allows replacing a single category and leaving the others alone' do
|
515
|
+
index[:title].replace Book.new('one', 'Replaced', 'Notindexed')
|
516
|
+
|
517
|
+
books.search('Title').ids.should == []
|
518
|
+
books.search('Replaced').ids.should == ['one']
|
519
|
+
|
520
|
+
books.search('Notindexed').ids.should == []
|
521
|
+
books.search('Author').ids.should == ['one']
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
context 'with partial' do
|
526
|
+
it 'finds the first entry' do
|
527
|
+
books.search('Titl').ids.should == ['one']
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'allows removing something' do
|
531
|
+
index.remove "one"
|
532
|
+
end
|
533
|
+
it 'is not findable anymore after removing' do
|
534
|
+
books.search('Titl').ids.should == ['one']
|
535
|
+
|
536
|
+
index.remove "one"
|
537
|
+
|
538
|
+
books.search('Titl').ids.should == []
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'allows adding something' do
|
542
|
+
index.add Book.new('two', 'Title2', 'Author2')
|
543
|
+
end
|
544
|
+
it 'is findable after adding' do
|
545
|
+
books.search('Titl').ids.should == ['one']
|
546
|
+
|
547
|
+
index.add Book.new('two', 'Title New', 'Author New')
|
548
|
+
|
549
|
+
books.search('Titl').ids.should == ['two', 'one']
|
550
|
+
end
|
551
|
+
|
552
|
+
it 'allows replacing something' do
|
553
|
+
index.replace Book.new('one', 'Title New', 'Author New')
|
554
|
+
end
|
555
|
+
it 'is findable after replacing' do
|
556
|
+
books.search('Ne').ids.should == []
|
557
|
+
|
558
|
+
index.replace Book.new('one', 'Title New', 'Author New')
|
559
|
+
|
560
|
+
books.search('Ne').ids.should == ['one', 'one']
|
561
|
+
end
|
562
|
+
it 'handles more complex cases' do
|
563
|
+
books.search('Ne').ids.should == []
|
564
|
+
|
565
|
+
index.replace Book.new('one', 'Title New', 'Author New')
|
566
|
+
|
567
|
+
books.search('title:Ne').ids.should == ['one']
|
568
|
+
end
|
569
|
+
it 'handles more complex cases' do
|
570
|
+
index.remove "one"
|
571
|
+
|
572
|
+
books.search('Titl').ids.should == []
|
573
|
+
|
574
|
+
index.replace Book.new('one', 'Title New', 'Author New')
|
575
|
+
|
576
|
+
books.search('title:Ne').ids.should == ['one']
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
context 'non-partial' do
|
581
|
+
it 'finds the first entry' do
|
582
|
+
books.search('Titl').ids.should == ['one']
|
583
|
+
end
|
584
|
+
|
585
|
+
it 'allows removing something' do
|
586
|
+
index.remove "one"
|
587
|
+
end
|
588
|
+
it 'is not findable anymore after removing' do
|
589
|
+
books.search('Titl').ids.should == ['one']
|
590
|
+
|
591
|
+
index.remove :one
|
592
|
+
|
593
|
+
books.search('Titl').ids.should == []
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'allows adding something' do
|
597
|
+
index.add Book.new("two", "Title2", "Author2")
|
598
|
+
end
|
599
|
+
it 'is findable after adding' do
|
600
|
+
books.search('Titl').ids.should == ['one']
|
601
|
+
|
602
|
+
index.add Book.new("two", "Title New", "Author New")
|
603
|
+
|
604
|
+
books.search('Titl').ids.should == ['two', 'one']
|
605
|
+
end
|
606
|
+
|
607
|
+
it 'allows replacing something' do
|
608
|
+
index.replace Book.new("one", "Title New", "Author New")
|
609
|
+
end
|
610
|
+
it 'is findable after replacing' do
|
611
|
+
books.search('Ne').ids.should == []
|
612
|
+
|
613
|
+
index.replace Book.new("one", "Title New", "Author New")
|
614
|
+
|
615
|
+
books.search('Ne').ids.should == ['one', 'one']
|
616
|
+
end
|
617
|
+
it 'handles more complex cases' do
|
618
|
+
books.search('Ne').ids.should == []
|
619
|
+
|
620
|
+
index.replace Book.new("one", "Title New", "Author New")
|
621
|
+
|
622
|
+
books.search('title:Ne').ids.should == ['one']
|
623
|
+
end
|
624
|
+
it 'handles more complex cases' do
|
625
|
+
index.remove "one"
|
626
|
+
|
627
|
+
books.search('Titl').ids.should == []
|
628
|
+
|
629
|
+
index.replace Book.new("one", "Title New", "Author New")
|
630
|
+
|
631
|
+
books.search('title:Ne').ids.should == ['one']
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
context 'similarity' do
|
636
|
+
it 'finds the first entry' do
|
637
|
+
books.search('Authr~').ids.should == ['one']
|
638
|
+
end
|
639
|
+
|
640
|
+
it 'allows removing something' do
|
641
|
+
index.remove "one"
|
642
|
+
end
|
643
|
+
it 'is not findable anymore after removing' do
|
644
|
+
books.search('Authr~').ids.should == ['one']
|
645
|
+
|
646
|
+
index.remove "one"
|
647
|
+
|
648
|
+
books.search('Authr~').ids.should == []
|
649
|
+
end
|
650
|
+
|
651
|
+
it 'allows adding something' do
|
652
|
+
index.add Book.new("two", "Title2", "Author2")
|
653
|
+
end
|
654
|
+
it 'is findable after adding' do
|
655
|
+
books.search('Authr~').ids.should == ['one']
|
656
|
+
|
657
|
+
index.add Book.new("two", "Title New", "Author New")
|
658
|
+
|
659
|
+
books.search('Authr~').ids.should == ['two', 'one']
|
660
|
+
end
|
661
|
+
|
662
|
+
it 'allows replacing something' do
|
663
|
+
index.replace Book.new("one", "Title New", "Author New")
|
664
|
+
end
|
665
|
+
it 'is findable after replacing' do
|
666
|
+
books.search('Nuw~').ids.should == []
|
667
|
+
|
668
|
+
index.replace Book.new("one", "Title New", "Author New")
|
669
|
+
|
670
|
+
books.search('Nuw~').ids.should == ['one']
|
671
|
+
end
|
672
|
+
it 'handles more complex cases' do
|
673
|
+
books.search('Now~').ids.should == []
|
674
|
+
|
675
|
+
index.replace Book.new("one", "Title New", "Author New")
|
676
|
+
|
677
|
+
books.search('author:Now~').ids.should == ['one']
|
678
|
+
end
|
679
|
+
it 'handles more complex cases' do
|
680
|
+
index.remove "one"
|
681
|
+
|
682
|
+
books.search('Athr~').ids.should == []
|
683
|
+
|
684
|
+
index.replace Book.new("one", "Title New", "Author New")
|
685
|
+
|
686
|
+
books.search('author:Athr~').ids.should == ['one']
|
687
|
+
end
|
688
|
+
it 'handles more complex cases' do
|
689
|
+
books.search('Athr~').ids.should == ['one']
|
690
|
+
|
691
|
+
index.replace Book.new("two", "Title New", "Author New")
|
692
|
+
index.add Book.new("three", "TTL", "AUTHR")
|
693
|
+
|
694
|
+
# Note: Allocations are [:two, :one], then [:three].
|
695
|
+
#
|
696
|
+
books.search('author:Athr~').ids.should == ['two', 'one', 'three']
|
697
|
+
end
|
698
|
+
end
|
699
|
+
end
|
476
700
|
|
477
701
|
end
|
@@ -5,7 +5,7 @@ require 'sqlite3'
|
|
5
5
|
describe Picky::Backends::SQLite::Array do
|
6
6
|
|
7
7
|
context 'hash-based indexes' do
|
8
|
-
let(:db) { described_class.new 'spec/temp/some/cache/path/to/file' }
|
8
|
+
let(:db) { described_class.new 'spec/temp/some/other/cache/path/to/file' }
|
9
9
|
|
10
10
|
describe 'dump' do
|
11
11
|
it 'forwards to the given hash' do
|
@@ -67,13 +67,13 @@ describe Picky::Backends::SQLite::Array do
|
|
67
67
|
|
68
68
|
describe 'to_s' do
|
69
69
|
it 'returns the cache path with the default file extension' do
|
70
|
-
db.to_s.should == 'Picky::Backends::SQLite::Array(spec/temp/some/cache/path/to/file.sqlite3)'
|
70
|
+
db.to_s.should == 'Picky::Backends::SQLite::Array(spec/temp/some/other/cache/path/to/file.sqlite3)'
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
75
|
context 'hash-based indexes' do
|
76
|
-
let(:db) { described_class.new 'spec/temp/some/cache/path/to/file', realtime: true }
|
76
|
+
let(:db) { described_class.new 'spec/temp/some/other/cache/path/to/file', realtime: true }
|
77
77
|
|
78
78
|
describe 'dump' do
|
79
79
|
it 'forwards to the given hash' do
|
@@ -135,7 +135,7 @@ describe Picky::Backends::SQLite::Array do
|
|
135
135
|
|
136
136
|
describe 'to_s' do
|
137
137
|
it 'returns the cache path with the default file extension' do
|
138
|
-
db.to_s.should == 'Picky::Backends::SQLite::Array(spec/temp/some/cache/path/to/file.sqlite3)'
|
138
|
+
db.to_s.should == 'Picky::Backends::SQLite::Array(spec/temp/some/other/cache/path/to/file.sqlite3)'
|
139
139
|
end
|
140
140
|
end
|
141
141
|
end
|
@@ -5,7 +5,7 @@ require 'sqlite3'
|
|
5
5
|
describe Picky::Backends::SQLite::Value do
|
6
6
|
|
7
7
|
context 'hash-based indexes' do
|
8
|
-
let(:db) { described_class.new 'spec/temp/some/cache/path/to/file' }
|
8
|
+
let(:db) { described_class.new 'spec/temp/some/other/cache/path/to/file' }
|
9
9
|
|
10
10
|
describe 'dump' do
|
11
11
|
it 'forwards to the given hash' do
|
@@ -67,7 +67,7 @@ describe Picky::Backends::SQLite::Value do
|
|
67
67
|
|
68
68
|
describe 'to_s' do
|
69
69
|
it 'returns the cache path with the default file extension' do
|
70
|
-
db.to_s.should == 'Picky::Backends::SQLite::Value(spec/temp/some/cache/path/to/file.sqlite3)'
|
70
|
+
db.to_s.should == 'Picky::Backends::SQLite::Value(spec/temp/some/other/cache/path/to/file.sqlite3)'
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -102,6 +102,9 @@ describe Picky::Bundle do
|
|
102
102
|
end
|
103
103
|
|
104
104
|
describe 'load' do
|
105
|
+
before(:each) do
|
106
|
+
@bundle.dump # Create an index first.
|
107
|
+
end
|
105
108
|
it 'should trigger loads' do
|
106
109
|
@bundle.should_receive(:load_inverted).once.with
|
107
110
|
@bundle.should_receive(:load_weights).once.with
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: picky
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.12.
|
4
|
+
version: 4.12.10
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-02-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 4.12.
|
37
|
+
version: 4.12.10
|
38
38
|
type: :development
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 4.12.
|
45
|
+
version: 4.12.10
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: text
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|