silver 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +30 -0
- data/lib/silver/search.rb +1 -1
- data/silver.gemspec +1 -1
- metadata +59 -59
data/README.markdown
CHANGED
@@ -7,27 +7,45 @@ Silver is a lightweight, redis-backed database cacher and indexer.
|
|
7
7
|
As it says on the tin, Silver is going to make your database queries much faster. Now it is no secret that Redis is fantastic to use as a cache/index. However, you have to write the same boilerplate to use it as cache over and over: find most recent cached entry, look for newer entries in the database, cache it to redis, combine with old results. Rinse, repeat.
|
8
8
|
The goal of Silver is so that you never have to do that again. Rather than connecting to the database/service for you, you simply wrap your calls in Silver and it does the rest. This means you can use silver to speed up calls to databases, calls APIs, CURLS, really whatever you want.
|
9
9
|
|
10
|
+
### Dependency Note
|
11
|
+
Silver require a version of Redis >= 2.0 running on your computer
|
12
|
+
Runtime gem dependincies are:
|
13
|
+
|
14
|
+
* redis ~> 2.1.1
|
15
|
+
* yajl-ruby >= 0.7.7
|
16
|
+
* text ~> 0.2.0
|
17
|
+
|
10
18
|
### A Simple Caching Example
|
11
19
|
|
12
20
|
First make sure you have Silver installed.
|
21
|
+
|
13
22
|
gem install silver
|
23
|
+
|
14
24
|
Now, let's pretend you have an app that queries your database for entries frequently. Entries are added frequently. Furthermore, you only want Entries that come from a specific blog, blog #12. Also you want to grab something from an association of the Entry row in the database. Let's say the author's name.
|
15
25
|
First, instantiate a new cache object.
|
26
|
+
|
16
27
|
cache = Silver::Cache.new("12_entries","created_time") do |date|
|
17
28
|
Entry.all(:order => :created_time.desc, :created_time.gt => date, :blog_id => 12)
|
18
29
|
end
|
30
|
+
|
19
31
|
The first paramater passed to the constructor is the name you want to give to this cache in Redis as Silver allows to creates as many caches for different queries as you would like. The second paramater is the name of the field that you will be using to determine if there are new entries. Finally, you pass the constructor a block that will receive the date of the newest cached entry from Redis. You must return the entries in reverse chronological order for Silver to be able to keep them in order. Silver will then query the database/service for newer entries when the instance's find method is called.
|
32
|
+
|
20
33
|
results = cache.find do |entry|
|
21
34
|
attrs = entry.attributes
|
22
35
|
author = {:author_name => entry.author[:name]}
|
23
36
|
attrs.merge author
|
24
37
|
end
|
38
|
+
|
25
39
|
The find method of a cache instance takes a block that will be called for every new entry. The results of the block call should be a hash that will be stored in the cache. The whole thing will be converted into JSON and stashed in the Redis cache. From now on the database will never have to be hit again to return this value. The find method returns an array of all the results old and new from the Redis cache.
|
26
40
|
If you just want to read from the cache without hitting the database, simply call find without a block and with a single param: false
|
41
|
+
|
27
42
|
results = cache.find(false)
|
43
|
+
|
28
44
|
Currently, the cache does not support the changing of cached entries and is, thus, intended for data that is unlikely to change once it has been written to the database. This feature will be included in future releases of Silver.
|
29
45
|
Finally, Silver provides a cull method.
|
46
|
+
|
30
47
|
cache.cull(30)
|
48
|
+
|
31
49
|
This will cut the Redis cache down to the 30 most recent items.
|
32
50
|
|
33
51
|
### A Simple Indexing Example
|
@@ -35,20 +53,28 @@ This will cut the Redis cache down to the 30 most recent items.
|
|
35
53
|
However, Silver is not just a simple cache. It can also be used to index a database. It is optimized to index based on short text, such as names, captions, tag lists, excerpts, tweets etc. There is nothing stopping you from using on longer fields such as body text except the size of your memory alloted to Redis. Silver uses a stupidly simple fuzzy text search. The search will likely be augmented in the future.
|
36
54
|
Here's how you would index a mess of photos by their captions, falling back on their filename if no caption is given.
|
37
55
|
First, instantiate a new index object.
|
56
|
+
|
38
57
|
index = Silver::Index.new("blog_pictures","created_time") do |date|
|
39
58
|
Picture.all(:order => :created_time.desc, :created_time.gt => date)
|
40
59
|
end
|
60
|
+
|
41
61
|
This is the same deal as before with Silver::Cache: redis key name, time field, ordering block.
|
42
62
|
Next, call the find_and_update method of the instance.
|
63
|
+
|
43
64
|
index.find_and_update do |result|
|
44
65
|
output = result.label || result.filename || ""
|
45
66
|
id = result.id
|
46
67
|
[id,output]
|
47
68
|
end
|
69
|
+
|
48
70
|
Find_and_update takes a block that will be called for each db-fetched result. This block should return a two item array of the row's id, first, and the value we are using for indexing second. As you can see in the example, Silver allows you to mix fields to use to index. It let's you do anything you want actually as long as an id and a corresponding value are returned. After calling find_and_update, your database is indexed and ready to be searched. Say, we wanted to search for photos of "Barack Obama":
|
71
|
+
|
49
72
|
search = Silver::Search.new("Barack Obama","blog_pictures")
|
73
|
+
|
50
74
|
The constructor takes a string to search for and the name of Redis key storing the index. To actually perform the search:
|
75
|
+
|
51
76
|
search.perform{|id| Picture.get(id)}
|
77
|
+
|
52
78
|
The perform method takes a block that will be passed the ids of all the id's whose indexes match the query. Perform will return an array of database/service objects for you to then interact with as you please.
|
53
79
|
|
54
80
|
### A note about the shortcoming of the search.
|
@@ -58,9 +84,13 @@ As Silver is currently in beta, it's search could use some work (feel free to co
|
|
58
84
|
### Non-standard configurations
|
59
85
|
|
60
86
|
Every initializer in Silver takes, in addition to the parameters shown above, an optional options hash for Redis as the third parameter.
|
87
|
+
|
61
88
|
cache = Silver::Cache.new("12_entries","created_time",{:host => "127.0.0.1",:port => "6969"})
|
89
|
+
|
62
90
|
Also, the search initializer for Silver's indexing takes optional number and offset paramater for pagination. Default is no offest and 30 results returned.
|
91
|
+
|
63
92
|
search = Silver::Search.new("Barack Obama","blog_pictures",{:host => "127.0.0.1",:port => "6969"},50,10)
|
93
|
+
|
64
94
|
This will return results 10-60.
|
65
95
|
|
66
96
|
### Rocco Annotated Source
|
data/lib/silver/search.rb
CHANGED
@@ -38,7 +38,7 @@ module Silver
|
|
38
38
|
phones = self.find_matching_phones(phones)
|
39
39
|
phones
|
40
40
|
end
|
41
|
-
results = morphed_words.reduce{|memo,obj| memo & obj}.slice(@offset,@
|
41
|
+
results = morphed_words.reduce{|memo,obj| memo & obj}.slice(@offset,@number)
|
42
42
|
results.map{|result| accessor.call(result)}
|
43
43
|
end
|
44
44
|
|
data/silver.gemspec
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: silver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Erik Hin-tone
|
@@ -19,9 +19,9 @@ date: 2011-01-31 00:00:00 -05:00
|
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
22
|
+
name: rspec
|
23
23
|
prerelease: false
|
24
|
-
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
@@ -32,12 +32,12 @@ dependencies:
|
|
32
32
|
- 3
|
33
33
|
- 0
|
34
34
|
version: 2.3.0
|
35
|
-
name: rspec
|
36
|
-
requirement: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
35
|
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: bundler
|
39
39
|
prerelease: false
|
40
|
-
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
@@ -48,12 +48,12 @@ dependencies:
|
|
48
48
|
- 0
|
49
49
|
- 0
|
50
50
|
version: 1.0.0
|
51
|
-
name: bundler
|
52
|
-
requirement: *id002
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
51
|
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: jeweler
|
55
55
|
prerelease: false
|
56
|
-
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
@@ -64,12 +64,12 @@ dependencies:
|
|
64
64
|
- 5
|
65
65
|
- 2
|
66
66
|
version: 1.5.2
|
67
|
-
name: jeweler
|
68
|
-
requirement: *id003
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
67
|
type: :development
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rcov
|
71
71
|
prerelease: false
|
72
|
-
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ">="
|
@@ -78,12 +78,12 @@ dependencies:
|
|
78
78
|
segments:
|
79
79
|
- 0
|
80
80
|
version: "0"
|
81
|
-
name: rcov
|
82
|
-
requirement: *id004
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
81
|
type: :development
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: redis
|
85
85
|
prerelease: false
|
86
|
-
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
87
|
none: false
|
88
88
|
requirements:
|
89
89
|
- - ~>
|
@@ -94,12 +94,12 @@ dependencies:
|
|
94
94
|
- 1
|
95
95
|
- 1
|
96
96
|
version: 2.1.1
|
97
|
-
name: redis
|
98
|
-
requirement: *id005
|
99
|
-
- !ruby/object:Gem::Dependency
|
100
97
|
type: :development
|
98
|
+
version_requirements: *id005
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: yajl-ruby
|
101
101
|
prerelease: false
|
102
|
-
|
102
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
103
103
|
none: false
|
104
104
|
requirements:
|
105
105
|
- - ">="
|
@@ -110,12 +110,12 @@ dependencies:
|
|
110
110
|
- 7
|
111
111
|
- 7
|
112
112
|
version: 0.7.7
|
113
|
-
name: yajl-ruby
|
114
|
-
requirement: *id006
|
115
|
-
- !ruby/object:Gem::Dependency
|
116
113
|
type: :development
|
114
|
+
version_requirements: *id006
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: text
|
117
117
|
prerelease: false
|
118
|
-
|
118
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
119
119
|
none: false
|
120
120
|
requirements:
|
121
121
|
- - ~>
|
@@ -126,12 +126,12 @@ dependencies:
|
|
126
126
|
- 2
|
127
127
|
- 0
|
128
128
|
version: 0.2.0
|
129
|
-
name: text
|
130
|
-
requirement: *id007
|
131
|
-
- !ruby/object:Gem::Dependency
|
132
129
|
type: :development
|
130
|
+
version_requirements: *id007
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: dm-core
|
133
133
|
prerelease: false
|
134
|
-
|
134
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
135
135
|
none: false
|
136
136
|
requirements:
|
137
137
|
- - ~>
|
@@ -142,12 +142,12 @@ dependencies:
|
|
142
142
|
- 0
|
143
143
|
- 0
|
144
144
|
version: 1.0.0
|
145
|
-
name: dm-core
|
146
|
-
requirement: *id008
|
147
|
-
- !ruby/object:Gem::Dependency
|
148
145
|
type: :development
|
146
|
+
version_requirements: *id008
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: dm-sqlite-adapter
|
149
149
|
prerelease: false
|
150
|
-
|
150
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
151
151
|
none: false
|
152
152
|
requirements:
|
153
153
|
- - ~>
|
@@ -158,12 +158,12 @@ dependencies:
|
|
158
158
|
- 0
|
159
159
|
- 0
|
160
160
|
version: 1.0.0
|
161
|
-
|
162
|
-
|
161
|
+
type: :development
|
162
|
+
version_requirements: *id009
|
163
163
|
- !ruby/object:Gem::Dependency
|
164
|
-
|
164
|
+
name: redis
|
165
165
|
prerelease: false
|
166
|
-
|
166
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
167
167
|
none: false
|
168
168
|
requirements:
|
169
169
|
- - ~>
|
@@ -174,12 +174,12 @@ dependencies:
|
|
174
174
|
- 1
|
175
175
|
- 1
|
176
176
|
version: 2.1.1
|
177
|
-
name: redis
|
178
|
-
requirement: *id010
|
179
|
-
- !ruby/object:Gem::Dependency
|
180
177
|
type: :runtime
|
178
|
+
version_requirements: *id010
|
179
|
+
- !ruby/object:Gem::Dependency
|
180
|
+
name: yajl-ruby
|
181
181
|
prerelease: false
|
182
|
-
|
182
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
183
183
|
none: false
|
184
184
|
requirements:
|
185
185
|
- - ">="
|
@@ -190,12 +190,12 @@ dependencies:
|
|
190
190
|
- 7
|
191
191
|
- 7
|
192
192
|
version: 0.7.7
|
193
|
-
name: yajl-ruby
|
194
|
-
requirement: *id011
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
193
|
type: :runtime
|
194
|
+
version_requirements: *id011
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: text
|
197
197
|
prerelease: false
|
198
|
-
|
198
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
199
199
|
none: false
|
200
200
|
requirements:
|
201
201
|
- - ~>
|
@@ -206,12 +206,12 @@ dependencies:
|
|
206
206
|
- 2
|
207
207
|
- 0
|
208
208
|
version: 0.2.0
|
209
|
-
|
210
|
-
|
209
|
+
type: :runtime
|
210
|
+
version_requirements: *id012
|
211
211
|
- !ruby/object:Gem::Dependency
|
212
|
-
|
212
|
+
name: dm-core
|
213
213
|
prerelease: false
|
214
|
-
|
214
|
+
requirement: &id013 !ruby/object:Gem::Requirement
|
215
215
|
none: false
|
216
216
|
requirements:
|
217
217
|
- - ~>
|
@@ -222,12 +222,12 @@ dependencies:
|
|
222
222
|
- 0
|
223
223
|
- 0
|
224
224
|
version: 1.0.0
|
225
|
-
name: dm-core
|
226
|
-
requirement: *id013
|
227
|
-
- !ruby/object:Gem::Dependency
|
228
225
|
type: :development
|
226
|
+
version_requirements: *id013
|
227
|
+
- !ruby/object:Gem::Dependency
|
228
|
+
name: dm-sqlite-adapter
|
229
229
|
prerelease: false
|
230
|
-
|
230
|
+
requirement: &id014 !ruby/object:Gem::Requirement
|
231
231
|
none: false
|
232
232
|
requirements:
|
233
233
|
- - ~>
|
@@ -238,8 +238,8 @@ dependencies:
|
|
238
238
|
- 0
|
239
239
|
- 0
|
240
240
|
version: 1.0.0
|
241
|
-
|
242
|
-
|
241
|
+
type: :development
|
242
|
+
version_requirements: *id014
|
243
243
|
description: A lightweight, Redis-backed cacher and indexer for databases, REST API's, really anything you can query.
|
244
244
|
email: hinton.erik@gmail.com
|
245
245
|
executables: []
|