picky 4.12.8 → 4.12.10
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/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
|