picky 4.29.0 → 4.30.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a01f4947489880cd1c19284bff6650bba8d7079
4
- data.tar.gz: 5419b4f7d824585911cad72f99ce61a3b72c2b85
3
+ metadata.gz: 9c258f99e445068d45ccb32d4ce15f091567b9e6
4
+ data.tar.gz: cf5d8bb9200d1e4b6deea865b97a9c4c16d5a59c
5
5
  SHA512:
6
- metadata.gz: bdf8813d2f15b1e272f9e0bef421897eb578918e6fa63ad3004efc9c64cb7882e93d585defb80a6e420d532443691168dfbe05dd7aff60dcddeb886a53a79011
7
- data.tar.gz: 276a089695a6b2d2d69cfbdd92dcca544267920f3f002ae323bec4e67b63dbd927c5126b0beed1e9c1a86d43504892b10cb78ae0fc77bc7ed4aaeb5c537fae91
6
+ metadata.gz: 03347abb98159e3a9f5d1014f5d647b09dc47bbf8c4ad5ea65082dfbf5554c46b5736ecebc81a4d55354a3e86a7dc43a4dd18a994d36d4e5cb912143260d2d0a
7
+ data.tar.gz: f0feaaac50db053a2c8879d0a2f4613156f50a17c888bd55c10cc6fd694d79aa7f2423adfac9497a9a9c8615cd7aac1b69b3ec4ed387cbe9ab81238d499233fa
@@ -46,14 +46,13 @@ module Picky
46
46
  #
47
47
  # Does not add to realtime if static.
48
48
  #
49
- def add id, str_or_sym, where = :unshift, static = false
50
-
49
+ def add id, str_or_sym, method: :unshift, static: false, force_update: false
51
50
  # If static, indexing will be slower, but will use less
52
51
  # space in the end.
53
52
  #
54
53
  if static
55
54
  ids = @inverted[str_or_sym] ||= []
56
- ids.send where, id unless ids.include? id
55
+ ids.send method, id unless ids.include? id
57
56
  else
58
57
  # Use a generalized strategy.
59
58
  #
@@ -63,14 +62,25 @@ module Picky
63
62
  #
64
63
  ids = if str_or_syms && str_or_syms.include?(str_or_sym)
65
64
  ids = @inverted[str_or_sym] ||= []
65
+ # If updates are not forced, then do not add it to the
66
+ # index if it's in there already.
67
+ unless force_update
68
+ return if ids.include? id
69
+ end
66
70
  ids.delete id
67
- ids.send where, id
71
+ ids.send method, id
68
72
  else
69
73
  # Update the realtime index.
70
74
  #
71
75
  str_or_syms << str_or_sym # unless static
72
- ids = @inverted[str_or_sym] ||= []
73
- ids.send where, id
76
+ # TODO Add has_key? to index backends.
77
+ # ids = if @inverted.has_key?(str_or_sym)
78
+ # @inverted[str_or_sym]
79
+ # else
80
+ # @inverted[str_or_sym] = []
81
+ # end
82
+ ids = (@inverted[str_or_sym] ||= [])
83
+ ids.send method, id
74
84
  end
75
85
  end
76
86
 
@@ -80,7 +90,7 @@ module Picky
80
90
 
81
91
  # Similarity.
82
92
  #
83
- add_similarity str_or_sym, where
93
+ add_similarity str_or_sym, method: method
84
94
 
85
95
  # Return reference.
86
96
  #
@@ -89,7 +99,7 @@ module Picky
89
99
 
90
100
  # Add string/symbol to similarity index.
91
101
  #
92
- def add_similarity str_or_sym, where = :unshift
102
+ def add_similarity str_or_sym, method: :unshift
93
103
  if encoded = self.similarity_strategy.encode(str_or_sym)
94
104
  similars = @similarity[encoded] ||= []
95
105
 
@@ -104,9 +114,9 @@ module Picky
104
114
 
105
115
  # Partializes the text and then adds each.
106
116
  #
107
- def add_partialized id, text, where = :unshift, static = false
117
+ def add_partialized id, text, method: :unshift, static: false, force_update: false
108
118
  partialized text do |partial_text|
109
- add id, partial_text, where, static
119
+ add id, partial_text, method: method, static: static, force_update: force_update
110
120
  end
111
121
  end
112
122
  def partialized text, &block
@@ -60,7 +60,9 @@ module Picky
60
60
  def retrieve
61
61
  format = key_format?
62
62
  static = static?
63
- prepared.retrieve { |id, token| add_tokenized_token id, token, :<<, format, static }
63
+ prepared.retrieve do |id, token|
64
+ add_tokenized_token id, token, method: :<<, format: format, static: static, force_update: false
65
+ end
64
66
  end
65
67
 
66
68
  # Return the key format.
@@ -4,6 +4,20 @@ module Picky
4
4
 
5
5
  class Picky::IdNotGivenException < StandardError; end
6
6
 
7
+ # Adds and indexes this category of the
8
+ # given object.
9
+ #
10
+ # TODO Don't do this super-dynamically?
11
+ #
12
+ def add object, method: :unshift, force_update: false
13
+ data = if from.respond_to? :call
14
+ from.call(object)
15
+ else
16
+ object.send(from)
17
+ end
18
+ add_text object.send(id), data, method: method, force_update: force_update
19
+ end
20
+
7
21
  # Removes an indexed object with the
8
22
  # given id.
9
23
  #
@@ -13,25 +27,12 @@ module Picky
13
27
  partial.remove id
14
28
  end
15
29
 
16
- # Adds and indexes this category of the
17
- # given object.
18
- #
19
- # TODO Don't do this super-dynamically.
20
- #
21
- def add object, where = :unshift
22
- if from.respond_to? :call
23
- add_text object.send(id), from.call(object), where
24
- else
25
- add_text object.send(id), object.send(from), where
26
- end
27
- end
28
-
29
30
  # Removes the object's id, and then
30
31
  # adds it again.
31
32
  #
32
- def replace object, where = :unshift
33
+ def replace object, method: :unshift
33
34
  remove object.send id
34
- add object, where
35
+ add object, method: method
35
36
  end
36
37
 
37
38
  # Replaces just part of the indexed data.
@@ -51,19 +52,19 @@ module Picky
51
52
  # Add at the end.
52
53
  #
53
54
  def << thing
54
- add thing, __method__
55
+ add thing, method: __method__
55
56
  end
56
57
 
57
58
  # Add at the beginning.
58
59
  #
59
60
  def unshift thing
60
- add thing, __method__
61
+ add thing, method: __method__
61
62
  end
62
63
 
63
64
  # For the given id, adds the list of
64
65
  # strings to the index for the given id.
65
66
  #
66
- def add_text id, text_or_tokens, where = :unshift
67
+ def add_text id, text_or_tokens, method: :unshift, force_update: false
67
68
  # text_or_tokens = text_or_tokens.to_sym if @symbol_keys # SYMBOLS.
68
69
  tokens = nil
69
70
  if tokenizer
@@ -73,7 +74,9 @@ module Picky
73
74
  end
74
75
 
75
76
  format = key_format?
76
- tokens.each { |text| add_tokenized_token id, text, where, format }
77
+ tokens.each do |text|
78
+ add_tokenized_token id, text, method: method, format: format, force_update: force_update
79
+ end
77
80
  rescue NoMethodError => e
78
81
  show_informative_add_text_error_message_for e
79
82
  end
@@ -88,15 +91,15 @@ module Picky
88
91
 
89
92
  #
90
93
  #
91
- def add_tokenized_token id, text, where = :unshift, format = true, static = false
94
+ def add_tokenized_token id, text, method: :unshift, format: true, static: false, force_update: false
92
95
  return unless text
93
96
 
94
97
  id = id.send key_format if format
95
98
  text = text.to_sym if @symbol_keys # SYMBOLS.
96
99
  id.freeze
97
100
 
98
- exact.add id, text, where, static
99
- partial.add_partialized id, text, where, static
101
+ exact.add id, text, method: method, static: static, force_update: force_update
102
+ partial.add_partialized id, text, method: method, static: static, force_update: force_update
100
103
  rescue NoMethodError => e
101
104
  puts e.message
102
105
  raise %Q{The object id with text "#{text}" does not respond to method #{key_format}.}
@@ -30,7 +30,7 @@ class String
30
30
 
31
31
  if range
32
32
  unless (range.first.zero? && range.last == -1)
33
- sub = sub[range].freeze
33
+ sub = sub[range]
34
34
  end
35
35
  end
36
36
 
@@ -41,7 +41,7 @@ class String
41
41
  from_length = size if size < from_length
42
42
  from_length = 1 if from_length < 1
43
43
 
44
- size.downto(from_length + 1) { yield sub = sub.chop.freeze }
44
+ size.downto(from_length + 1) { yield sub = sub.chop }
45
45
 
46
46
  sub = nil
47
47
  end
@@ -5,7 +5,7 @@ module Picky
5
5
  class Index
6
6
 
7
7
  forward :remove, # aka "delete".
8
- :add, # aka "insert".
8
+ # :add, # aka "insert". # See below.
9
9
  :replace, # aka "delete then insert".
10
10
  :update,
11
11
  :replace_from,
@@ -16,13 +16,19 @@ module Picky
16
16
  # Add at the end.
17
17
  #
18
18
  def << thing
19
- add thing, __method__
19
+ add thing, method: __method__
20
20
  end
21
21
 
22
22
  # Add at the beginning (calls add).
23
23
  #
24
24
  def unshift thing
25
- add thing, __method__
25
+ add thing, method: __method__
26
+ end
27
+
28
+ # Add to the index using unshift.
29
+ #
30
+ def add thing, method: :unshift, force_update: false
31
+ categories.add thing, method: method, force_update: force_update
26
32
  end
27
33
 
28
34
  end
@@ -18,9 +18,22 @@ module Picky::Optimizers::Memory
18
18
 
19
19
  def deduplicate_hash hash, array_references
20
20
  hash.each do |k, ary|
21
- hash[k] = (array_references[ary] ||= ary)
21
+ stored_ary = if array_references.has_key?(ary)
22
+ array_references.fetch ary
23
+ else
24
+ # Prepare ary for reference cache.
25
+ compact_ary = compact ary
26
+ # Cache ary.
27
+ array_references.store ary, compact_ary
28
+ end
29
+
30
+ hash[k] = stored_ary
22
31
  end
23
32
  end
24
33
 
34
+ def compact ary
35
+ Array[*ary]
36
+ end
37
+
25
38
  end
26
39
  end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ describe "Memory leak?" do
6
+
7
+ before(:each) do
8
+ # Remove all indexes.
9
+ Picky::Indexes.clear_indexes
10
+
11
+ @index = Picky::Index.new :memory_optimization do
12
+ category :text1
13
+ category :text2
14
+ category :text3
15
+ category :text4
16
+ end
17
+
18
+ @thing = Struct.new(:id, :text1, :text2, :text3, :text4)
19
+ end
20
+
21
+ attr_reader :index, :thing
22
+
23
+ it 'does not leak' do
24
+ require 'objspace'
25
+
26
+ GC.start
27
+ memsize_without_added_thing = ObjectSpace.memsize_of_all(Array)
28
+ GC.start
29
+
30
+ index.add thing.new(1, 'one', 'two', 'three', 'four')
31
+
32
+ GC.start
33
+ memsize_with_added_thing = ObjectSpace.memsize_of_all(Array)
34
+ GC.start
35
+
36
+ index.add thing.new(1, 'one', 'two', 'three', 'four')
37
+
38
+ GC.start
39
+ memsize_with_readded_thing = ObjectSpace.memsize_of_all(Array)
40
+ GC.start
41
+
42
+ memsize_with_readded_thing.should == memsize_with_added_thing
43
+ end
44
+
45
+ end
@@ -4,20 +4,23 @@ require 'spec_helper'
4
4
 
5
5
  describe "Memory optimization" do
6
6
 
7
- it 'saves memory' do
7
+ before(:each) do
8
8
  # Remove all indexes.
9
9
  Picky::Indexes.clear_indexes
10
10
 
11
- index = Picky::Index.new :memory_optimization do
11
+ @index = Picky::Index.new :memory_optimization do
12
12
  category :text1
13
13
  category :text2
14
14
  category :text3
15
15
  category :text4
16
16
  end
17
- try = Picky::Search.new index
18
-
19
- thing = Struct.new(:id, :text1, :text2, :text3, :text4)
20
17
 
18
+ @thing = Struct.new(:id, :text1, :text2, :text3, :text4)
19
+ end
20
+
21
+ attr_reader :index, :thing
22
+
23
+ it 'saves memory' do
21
24
  require 'objspace'
22
25
 
23
26
  GC.start
@@ -38,7 +41,41 @@ describe "Memory optimization" do
38
41
  memsize_with_optimized_memory = ObjectSpace.memsize_of_all(Array)
39
42
  GC.start
40
43
 
44
+ # Still larger than with nothing.
45
+ memsize_without_added_thing.should < memsize_with_optimized_memory
46
+ # But smaller than with added.
41
47
  memsize_with_optimized_memory.should < memsize_with_added_thing
42
48
  end
49
+
50
+ it 'saves a certain amount of memory' do
51
+ require 'objspace'
52
+
53
+ GC.start
54
+ memsize_without_added_thing = ObjectSpace.memsize_of_all(Array)
55
+ GC.start
56
+
57
+ index.add thing.new(1, 'one', 'two', 'three', 'four')
58
+
59
+ GC.start
60
+ memsize_with_added_thing = ObjectSpace.memsize_of_all(Array)
61
+ GC.start
62
+
63
+ 10.times do |i|
64
+ index.add thing.new(i+1, 'one', 'two', 'three', 'four')
65
+ end
66
+
67
+ GC.start
68
+ memsize_with_readded_thing = ObjectSpace.memsize_of_all(Array)
69
+ GC.start
70
+
71
+ Picky::Indexes.optimize_memory
72
+
73
+ GC.start
74
+ memsize_with_optimized_memory = ObjectSpace.memsize_of_all(Array)
75
+ GC.start
76
+
77
+ # Optimize saves some memory.
78
+ (memsize_with_optimized_memory + 2952).should == memsize_with_readded_thing
79
+ end
43
80
 
44
81
  end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+ #
3
+ require 'spec_helper'
4
+
5
+ # Shows that realime update data can be ignored if they are
6
+ # already in the index.
7
+ #
8
+ describe 'ignoring updates' do
9
+
10
+ it 'does not update the index if the updated data stayed the same' do
11
+ index = Picky::Index.new :books do
12
+ category :title
13
+ end
14
+
15
+ thing = Struct.new :id, :title
16
+ index.add thing.new(1, 'some title')
17
+ index.add thing.new(2, 'some title')
18
+
19
+ try = Picky::Search.new index
20
+
21
+ try.search('some').ids.should == [2, 1]
22
+
23
+ index.add thing.new(1, 'some title'), force_update: true
24
+
25
+ # Expected behavior.
26
+ try.search('some').ids.should == [1, 2]
27
+
28
+ index.add thing.new(2, 'some title') # force_update: false is the default.
29
+
30
+ # Not updated, since it was the exact same data everywhere.
31
+ try.search('some').ids.should == [1, 2]
32
+
33
+ index.add thing.new(2, 'some title'), force_update: false
34
+
35
+ # Not updated, since it was the exact same data everywhere.
36
+ try.search('some').ids.should == [1, 2]
37
+ end
38
+ end
@@ -185,7 +185,7 @@ describe 'Search#terminate_early' do
185
185
  try_fast.search('hello hello hello').ids
186
186
  end
187
187
  slow.should < 0.0005
188
- fast.should < 0.00025
188
+ fast.should < 0.0003
189
189
  (slow/fast).should >= 2
190
190
 
191
191
  try_slow = Picky::Search.new index
@@ -48,26 +48,27 @@ describe Picky::Category do
48
48
  end
49
49
  end
50
50
 
51
- describe 'retrieve' do
52
- it 'call the right thing' do
53
- prepared = double :prepared
54
- prepared.should_receive(:retrieve).at_least(1)
55
- .and_yield(1, :some_token)
56
- .and_yield(2, :some_token)
57
- .and_yield(3, :some_token)
58
- .and_yield(4, :some_token)
59
- .and_yield(5, :some_token)
60
- category.stub :prepared => prepared
61
-
62
- category.should_receive(:add_tokenized_token).once.with(1, :some_token, :<<, nil, nil)
63
- category.should_receive(:add_tokenized_token).once.with(2, :some_token, :<<, nil, nil)
64
- category.should_receive(:add_tokenized_token).once.with(3, :some_token, :<<, nil, nil)
65
- category.should_receive(:add_tokenized_token).once.with(4, :some_token, :<<, nil, nil)
66
- category.should_receive(:add_tokenized_token).once.with(5, :some_token, :<<, nil, nil)
67
-
68
- category.retrieve
69
- end
70
- end
51
+ # Replaced by functional specs.
52
+ # describe 'retrieve' do
53
+ # it 'call the right thing' do
54
+ # prepared = double :prepared
55
+ # prepared.should_receive(:retrieve).at_least(1)
56
+ # .and_yield(1, :some_token)
57
+ # .and_yield(2, :some_token)
58
+ # .and_yield(3, :some_token)
59
+ # .and_yield(4, :some_token)
60
+ # .and_yield(5, :some_token)
61
+ # category.stub :prepared => prepared
62
+ #
63
+ # category.should_receive(:add_tokenized_token).once.with(1, :some_token, :<<, nil, nil)
64
+ # category.should_receive(:add_tokenized_token).once.with(2, :some_token, :<<, nil, nil)
65
+ # category.should_receive(:add_tokenized_token).once.with(3, :some_token, :<<, nil, nil)
66
+ # category.should_receive(:add_tokenized_token).once.with(4, :some_token, :<<, nil, nil)
67
+ # category.should_receive(:add_tokenized_token).once.with(5, :some_token, :<<, nil, nil)
68
+ #
69
+ # category.retrieve
70
+ # end
71
+ # end
71
72
 
72
73
  describe 'key_format' do
73
74
  context 'category has its own key_format' do
@@ -26,7 +26,7 @@ describe Picky::CharacterSubstituters::Polish do
26
26
  it "is fast" do
27
27
  substituter.substitute 'ą' # Prerun
28
28
  result = performance_of { substituter.substitute('ą') }
29
- result.should < 0.00009
29
+ result.should < 0.0002
30
30
  end
31
31
  it "is fast" do
32
32
  result = performance_of { substituter.substitute('abcdefghijklmnopqrstuvwxyz1234567890') }
@@ -10,7 +10,7 @@ describe Symbol do
10
10
  @token = (((0..9).to_a)*10).to_s.to_sym
11
11
  end
12
12
  it "is fast" do
13
- performance_of { @token.each_subtoken { |subtoken| } }.should < 0.00065
13
+ performance_of { @token.each_subtoken { |subtoken| } }.should < 0.001
14
14
  end
15
15
  it 'is fast enough' do
16
16
  performance_of { @token.each_intoken { |intoken| } }.should < 0.0375
@@ -8,7 +8,7 @@ describe Picky do
8
8
  # THINK What to set default internal encoding to?
9
9
  #
10
10
  it 'sets the right internal encoding' do
11
- Encoding.default_internal.should == Encoding::UTF_8
11
+ Encoding.default_internal.should be_nil
12
12
  end
13
13
 
14
14
  it 'loads in a simple ruby environment with the defined requirements' do
@@ -79,7 +79,7 @@ describe Performant::Array do
79
79
 
80
80
  # Brute force.
81
81
  #
82
- performance_of { Performant::Array.memory_efficient_intersect(arys) }.should < 0.001
82
+ performance_of { Performant::Array.memory_efficient_intersect(arys) }.should < 0.002
83
83
  end
84
84
  it "should be optimal for 2 small arrays of 50/10_000" do
85
85
  arys = [(:'1'..:'50').to_a, (:'10_000'..:'20_000').to_a << 7]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: picky
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.29.0
4
+ version: 4.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Hanke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-28 00:00:00.000000000 Z
11
+ date: 2015-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -237,6 +237,7 @@ files:
237
237
  - spec/functional/ignore_allocations_spec.rb
238
238
  - spec/functional/ignore_spec.rb
239
239
  - spec/functional/max_allocations_spec.rb
240
+ - spec/functional/memory_leak_spec.rb
240
241
  - spec/functional/multi_index_qualifier_spec.rb
241
242
  - spec/functional/no_dump_hint_spec.rb
242
243
  - spec/functional/no_tokenize_spec.rb
@@ -247,6 +248,7 @@ files:
247
248
  - spec/functional/or_spec.rb
248
249
  - spec/functional/pool_spec.rb
249
250
  - spec/functional/range_queries_spec.rb
251
+ - spec/functional/realtime_force_update_spec.rb
250
252
  - spec/functional/realtime_spec.rb
251
253
  - spec/functional/regression_spec.rb
252
254
  - spec/functional/reloading_spec.rb
@@ -422,6 +424,7 @@ test_files:
422
424
  - spec/functional/ignore_allocations_spec.rb
423
425
  - spec/functional/ignore_spec.rb
424
426
  - spec/functional/max_allocations_spec.rb
427
+ - spec/functional/memory_leak_spec.rb
425
428
  - spec/functional/multi_index_qualifier_spec.rb
426
429
  - spec/functional/no_dump_hint_spec.rb
427
430
  - spec/functional/no_tokenize_spec.rb
@@ -432,6 +435,7 @@ test_files:
432
435
  - spec/functional/or_spec.rb
433
436
  - spec/functional/pool_spec.rb
434
437
  - spec/functional/range_queries_spec.rb
438
+ - spec/functional/realtime_force_update_spec.rb
435
439
  - spec/functional/realtime_spec.rb
436
440
  - spec/functional/regression_spec.rb
437
441
  - spec/functional/reloading_spec.rb