similus 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,23 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2010 Horaci Cuevas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to
7
+ deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
@@ -0,0 +1,16 @@
1
+ LICENSES
2
+ README.rdoc
3
+ Rakefile
4
+ benchmarks/benchmark1.rb
5
+ benchmarks/benchmark2.rb
6
+ benchmarks/custom_benchmark.rb
7
+ benchmarks/redis.conf
8
+ init.rb
9
+ lib/similus.rb
10
+ lib/similus/config.rb
11
+ lib/similus/core.rb
12
+ lib/similus/redis.rb
13
+ test/add_activity_spec.rb
14
+ test/recommended_spec.rb
15
+ test/similar_spec.rb
16
+ Manifest
@@ -0,0 +1,80 @@
1
+ = Similus
2
+
3
+ Similus is a Ruby library that allows to find similar objects and recommendations using generated activity.
4
+ Examples of usage:
5
+
6
+ * Find similar articles to another one based on what other users also viewed.
7
+ * Recommend articles to a user based on similar activity of other users.
8
+
9
+ == Authors
10
+
11
+ {Horaci Cuevas}[http://github.com/horaci] <horaci@gmail.com>
12
+
13
+ == Quick overview
14
+
15
+ * Setup
16
+ * Store activity
17
+ * Show similar objects
18
+ * Show recommended objects
19
+
20
+ == Setup
21
+
22
+ Before using Similus, you need to setup the redis configuration. In rails this can be done inside a preinitializer in the config/preinitializers folder.
23
+
24
+ Similus.config do |config|
25
+ config.backend = :redis
26
+ config.redis_server = "localhost:6379"
27
+ config.redis_db = 8
28
+ end
29
+
30
+ === Store activity
31
+
32
+ Locate where you want to store activity. For example, in Ruby on Rails, inside the show method of the ArticlesController class:
33
+
34
+ class ArticlesController < ApplicationController
35
+ def show
36
+ @article = Article.find(params[:id])
37
+ Similus.add_activity(current_user, :show, @article)
38
+ end
39
+ end
40
+
41
+ === Show similar objects
42
+
43
+ Once there is some activity stored by users, you can query for similar objects:
44
+
45
+ class ArticlesController < ApplicationController
46
+ def show
47
+ @article = Article.find(params[:id])
48
+ @similar_articles = Similus.similar_to(@article)
49
+ end
50
+ end
51
+
52
+ === Show recommended objects
53
+
54
+ Even better than just showing similar articles, show recommended articles for the user's previous activity when there is a logged in user:
55
+
56
+ class HomeController < ApplicationController
57
+ def index
58
+ @recommended_articles = Similus.recommended_for(current_user, :target => "Article")
59
+ end
60
+ end
61
+
62
+ == Configuring and installing Similus
63
+
64
+ As of current version, Similus only supports redis backend. Thus, you need the redis gem and a redis server started.
65
+
66
+ * Install Redis 2.0 from [http://code.google.com/p/redis/]
67
+
68
+ * Install the redis gem
69
+
70
+ gem install redis
71
+
72
+ * Install the Similus gem
73
+
74
+ gem install similus
75
+
76
+ == License
77
+
78
+ Copyright (c) 2010 Horaci Cuevas
79
+
80
+ See LICENSES for details.
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+ require 'spec/rake/spectask'
5
+
6
+ desc 'Default: run all similus tests'
7
+ task :default => :test
8
+
9
+ desc "Run all tests"
10
+ Spec::Rake::SpecTask.new('test') do |t|
11
+ t.spec_files = FileList['test/**/*.rb']
12
+ t.spec_opts = ["--color"]
13
+ end
14
+
15
+ Echoe.new('similus', '0.1.1') do |p|
16
+ p.description = "A ruby library to find similar objects and make recommendations based on activity of objects"
17
+ p.url = "http://github.com/horaci/similus"
18
+ p.author = "Horaci Cuevas"
19
+ p.email = "horaci @@ gmail.com"
20
+ p.ignore_pattern = ["tmp/*", "script/*"]
21
+ p.development_dependencies = []
22
+ end
@@ -0,0 +1,90 @@
1
+ require '../lib/similus.rb'
2
+ require './custom_benchmark.rb'
3
+
4
+ class SimilusBenchmark1
5
+ def configure_redis
6
+ Similus.config do |config|
7
+ config.backend = :redis
8
+ config.redis_server = "localhost:6379"
9
+ config.redis_db = 8
10
+ end
11
+ end
12
+
13
+ def test
14
+ configure_redis
15
+
16
+ [10,50,100,500,1_000,5_000,10_000,50_000,100_000,500_000,1_000_000].each do |t|
17
+ test_method(:add_activity, t, :param_types => [:users,:actions,:targets], :flush => true)
18
+ test_method(:similar_to, t, :repetitions => [t,100000].min, :method_options => {:load_objects => false})
19
+ test_method(:recommended_for, t, :repetitions => [t,100000].min, :method_options => {:load_objects => false})
20
+ end
21
+
22
+ CustomBenchmark.print_table
23
+ end
24
+
25
+ def test_method(method, t=1, options={})
26
+ options = {:param_types=>[:users], :flush=>false, :repetitions => t}.update(options)
27
+
28
+ # Preapre data
29
+ Similus.redis.flushdb if options[:flush]
30
+ users = []; actions = []; targets = []
31
+ options[:repetitions].times do |i|
32
+ users[i] = ["User", rand([2,t/10].max)+1]
33
+ actions[i] = [:view, :comment, :like].shuffle.first
34
+ targets[i] = [["Article", "Author", "User", "Comment"].shuffle.first, rand([2,t/100].max)+1]
35
+ end
36
+
37
+ # Repeat t times
38
+ CustomBenchmark.benchmark_block(method, t, options[:repetitions]) do
39
+ print "Start #{method} #{options[:repetitions]} (#{t}) times: "
40
+ options[:repetitions].times do |i|
41
+ print "." if i%1000 == 0 and i > 0
42
+ params = []
43
+ params << users[i] if options[:param_types].include?(:users)
44
+ params << actions[i] if options[:param_types].include?(:actions)
45
+ params << targets[i] if options[:param_types].include?(:targets)
46
+ params << options[:method_options] if options[:method_options]
47
+ Similus.send(method.to_sym, *params)
48
+ end
49
+ puts "Done!"
50
+ end
51
+ end
52
+ end
53
+
54
+ benchmark = SimilusBenchmark1.new
55
+ benchmark.test
56
+
57
+
58
+ # 28/09/2010
59
+ #
60
+ # (times) : add_activity | similar_to | recommended_for |
61
+ # 10 : 10.02 (1.00) | 3.45 (0.34) | 8.50 (0.85) |
62
+ # 50 : 39.04 (0.78) | 24.53 (0.49) | 45.48 (0.91) |
63
+ # 100 : 73.15 (0.73) | 55.42 (0.55) | 96.05 (0.96) |
64
+ # 500 : 422.46 (0.84) | 623.09 (1.25) | 1778.15 (3.56) |
65
+ # 1000 : 788.63 (0.79) | 1990.06 (1.99) | 4837.11 (4.84) |
66
+ # 5000 : 4295.17 (0.86) | 12390.42 (2.48) | 36720.16 (7.34) |
67
+ # 10000 : 8007.07 (0.80) | 41967.76 (4.20) | 105031.32 (10.50) |
68
+ # 50000 : 41792.52 (0.84) | 139241.77 (2.78) | 383507.61 (7.67) |
69
+ # 100000 : 85121.77 (0.85) | 467467.67 (4.67) | 1093418.17 (10.93) |
70
+ # 500000 : 487059.48 (0.97) | 1475465.49 (2.95) | 3576451.57 (7.15) |
71
+ # 1000000 : 992621.05 (0.99) | 4901504.93 (4.90) | 10251016.93 (10.25) | // 1.077.523.597 objects from similar
72
+ #
73
+
74
+ # 04/10/2010 - 1M activity dump size = 196MB
75
+ #
76
+ # +-----------+-----------------------+-----------------------+-----------------------+
77
+ # | (times) | add_activity (avg) | similar_to (avg) | recommended_for (avg) |
78
+ # +-----------+-----------------------+-----------------------+-----------------------+
79
+ # | 10 | 20.33 (2.03) | 3.43 (0.34) | 5.11 (0.51) |
80
+ # | 50 | 43.20 (0.86) | 21.45 (0.43) | 37.15 (0.74) |
81
+ # | 100 | 79.26 (0.79) | 47.26 (0.47) | 83.99 (0.84) |
82
+ # | 500 | 420.71 (0.84) | 645.66 (1.29) | 1233.73 (2.47) |
83
+ # | 1000 | 775.37 (0.78) | 2059.96 (2.06) | 3919.73 (3.92) |
84
+ # | 5000 | 4244.56 (0.85) | 13365.46 (2.67) | 31732.53 (6.35) |
85
+ # | 10000 | 8132.53 (0.81) | 46890.51 (4.69) | 103245.89 (10.32) |
86
+ # | 50000 | 40575.59 (0.81) | 184494.91 (3.69) | 421366.42 (8.43) |
87
+ # | 100000 | 83084.49 (0.83) | 662960.10 (6.63) | 1346657.15 (13.47) |
88
+ # | 500000 | 473529.20 (0.95) | 344602.52 (3.45) | 671415.21 (6.71) |
89
+ # | 1000000 | 969757.84 (0.97) | 566429.01 (5.66) | 986263.44 (9.86) |
90
+ # +-----------+-----------------------+-----------------------+-----------------------+
@@ -0,0 +1,92 @@
1
+ require '../lib/similus.rb'
2
+ require './custom_benchmark.rb'
3
+ require 'csv'
4
+ require 'pp'
5
+
6
+ # Configure redis
7
+ Similus.config do |config|
8
+ config.backend = :redis
9
+ config.redis_server = "localhost:6379"
10
+ config.redis_db = 7
11
+ end
12
+
13
+ # Clear data
14
+ Similus.clear_database!
15
+
16
+ # Download entree-database
17
+ unless File.directory? "./entree-database"
18
+ `wget http://archive.ics.uci.edu/ml/databases/entree/entree_data.tar.gz`
19
+ `mkdir entree-database && cd entree-database && tar -zxvf ../entree_data.tar.g`
20
+ end
21
+
22
+ # Load chicago restaurants
23
+ restaurants = {}
24
+ print "Loading restaurants... "
25
+ CSV.open('./entree-database/entree/data/chicago.txt','r', :col_sep => "\t").each do |row|
26
+ restaurants[row[0].to_i] = {
27
+ :name => row[1],
28
+ :features => row[2].split(" ").map(&:to_i)
29
+ }
30
+ end
31
+
32
+ puts "Done!"
33
+
34
+ features = {}
35
+ print "Loading features... "
36
+ CSV.open('./entree-database/entree/data/features.txt','r', :col_sep => "\t").each do |row|
37
+ features[row[0].to_i] = row[1]
38
+ end
39
+ puts "Done!"
40
+
41
+ # Load activity
42
+ users = {}
43
+ puts "Loading activity... "
44
+ Dir.glob(File.join("./entree-database/entree/session/", "session.*")).sort.each do |file|
45
+ print "File #{file}: "
46
+ pos = 0
47
+ CSV.open(file,'r', :col_sep => "\t").each do |row|
48
+ print "." if (pos += 1) % 100 == 0
49
+ date = row.shift; user = row.shift; origin =row.shift
50
+ pages = row.map { |x| x.gsub(/[^0-9]/, "").to_i }.reject { |x| x == 0 }
51
+
52
+ users[user] ||= {
53
+ :pages => [],
54
+ :landings => [],
55
+ }
56
+ users[user][:pages] += pages
57
+ users[user][:landings] << pages.last if pages.last > 0
58
+
59
+ pages.each do |page|
60
+ Similus.add_activity(["User",user], :view, ["Restaurant",page])
61
+ end
62
+ end
63
+ puts " Done!"
64
+ end
65
+
66
+ count = 0
67
+ total_score = 0
68
+ users.each do |user_key,user|
69
+ break if (count += 1) > 500 # First 500 users only
70
+ best_score = 0
71
+ best_choice = nil
72
+ Similus.recommended_for(["User",user_key]).each do |rec|
73
+ user[:landings].each do |landing|
74
+ rfm = (restaurants[rec[:id].to_i][:features] & restaurants[landing.to_i][:features]).size
75
+ if rfm > best_score
76
+ best_score = rfm
77
+ best_choice = rec[:id].to_i
78
+ end
79
+ end
80
+ end
81
+
82
+ print "#{best_score},"
83
+ total_score += best_score
84
+ end
85
+
86
+ puts " Done! --- Total: #{total_score}"
87
+
88
+ # control data
89
+
90
+
91
+
92
+
@@ -0,0 +1,41 @@
1
+ class CustomBenchmark
2
+ def self.benchmark_block(txtlabel, counter_container=0, times_repeated=nil)
3
+ benchmark[counter_container] ||= {}
4
+ now = Time.now.to_f
5
+ res = yield if block_given?
6
+ benchmark[counter_container][txtlabel] = {:total => (Time.now.to_f - now) * 1000, :times => times_repeated || counter_container}
7
+ res
8
+ end
9
+
10
+ def self.benchmark
11
+ @benchmark ||= {}
12
+ end
13
+
14
+ def self.print_table
15
+ labels = benchmark.first[1].keys
16
+ max_label_size = labels.map(&:size).max + 7
17
+ fmt_str = "|%10s |" + ("%#{max_label_size}s |" * labels.size) + "\n"
18
+
19
+ # Header
20
+ print_line(labels, max_label_size)
21
+ printf(fmt_str, "(times)", *(labels.map { |l| "#{l} (avg)"}))
22
+ print_line(labels, max_label_size)
23
+
24
+ # Body
25
+ benchmark.each do |t,bench|
26
+ values = labels.map do |txtlabel|
27
+ sprintf("%.2f", bench[txtlabel][:total]) + " (" + sprintf("%.2f", bench[txtlabel][:total]/bench[txtlabel][:times]) + ")"
28
+ end
29
+ printf(fmt_str, t, *values)
30
+ end
31
+
32
+ # End line
33
+ print_line(labels, max_label_size)
34
+ end
35
+
36
+ def self.print_line(labels, max_label_size)
37
+ format = "+%10s-+" + ("%#{max_label_size}s-+" * labels.size) + "\n"
38
+ label_lines = ['-'*max_label_size]*labels.size
39
+ printf(format, "-"*10, *label_lines)
40
+ end
41
+ end
@@ -0,0 +1,312 @@
1
+ # Redis configuration file example
2
+
3
+ # Note on units: when memory size is needed, it is possible to specifiy
4
+ # it in the usual form of 1k 5GB 4M and so forth:
5
+ #
6
+ # 1k => 1000 bytes
7
+ # 1kb => 1024 bytes
8
+ # 1m => 1000000 bytes
9
+ # 1mb => 1024*1024 bytes
10
+ # 1g => 1000000000 bytes
11
+ # 1gb => 1024*1024*1024 bytes
12
+ #
13
+ # units are case insensitive so 1GB 1Gb 1gB are all the same.
14
+
15
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
16
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
17
+ daemonize yes
18
+
19
+ # When running daemonized, Redis writes a pid file in /var/run/redis.pid by
20
+ # default. You can specify a custom pid file location here.
21
+ pidfile /var/run/redis.pid
22
+
23
+ # Accept connections on the specified port, default is 6379
24
+ port 6379
25
+
26
+ # If you want you can bind a single interface, if the bind option is not
27
+ # specified all the interfaces will listen for incoming connections.
28
+ #
29
+ # bind 127.0.0.1
30
+
31
+ # Close the connection after a client is idle for N seconds (0 to disable)
32
+ timeout 300
33
+
34
+ # Set server verbosity to 'debug'
35
+ # it can be one of:
36
+ # debug (a lot of information, useful for development/testing)
37
+ # verbose (many rarely useful info, but not a mess like the debug level)
38
+ # notice (moderately verbose, what you want in production probably)
39
+ # warning (only very important / critical messages are logged)
40
+ loglevel verbose
41
+
42
+ # Specify the log file name. Also 'stdout' can be used to force
43
+ # Redis to log on the standard output. Note that if you use standard
44
+ # output for logging but daemonize, logs will be sent to /dev/null
45
+ logfile stdout
46
+
47
+ # Set the number of databases. The default database is DB 0, you can select
48
+ # a different one on a per-connection basis using SELECT <dbid> where
49
+ # dbid is a number between 0 and 'databases'-1
50
+ databases 16
51
+
52
+ ################################ SNAPSHOTTING #################################
53
+ #
54
+ # Save the DB on disk:
55
+ #
56
+ # save <seconds> <changes>
57
+ #
58
+ # Will save the DB if both the given number of seconds and the given
59
+ # number of write operations against the DB occurred.
60
+ #
61
+ # In the example below the behaviour will be to save:
62
+ # after 900 sec (15 min) if at least 1 key changed
63
+ # after 300 sec (5 min) if at least 10 keys changed
64
+ # after 60 sec if at least 10000 keys changed
65
+ #
66
+ # Note: you can disable saving at all commenting all the "save" lines.
67
+
68
+ save 900 1
69
+ save 300 10
70
+ save 60 10000
71
+
72
+ # Compress string objects using LZF when dump .rdb databases?
73
+ # For default that's set to 'yes' as it's almost always a win.
74
+ # If you want to save some CPU in the saving child set it to 'no' but
75
+ # the dataset will likely be bigger if you have compressible values or keys.
76
+ rdbcompression yes
77
+
78
+ # The filename where to dump the DB
79
+ dbfilename dump.rdb
80
+
81
+ # The working directory.
82
+ #
83
+ # The DB will be written inside this directory, with the filename specified
84
+ # above using the 'dbfilename' configuration directive.
85
+ #
86
+ # Also the Append Only File will be created inside this directory.
87
+ #
88
+ # Note that you must specify a directory here, not a file name.
89
+ dir ./
90
+
91
+ ################################# REPLICATION #################################
92
+
93
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
94
+ # another Redis server. Note that the configuration is local to the slave
95
+ # so for example it is possible to configure the slave to save the DB with a
96
+ # different interval, or to listen to another port, and so on.
97
+ #
98
+ # slaveof <masterip> <masterport>
99
+
100
+ # If the master is password protected (using the "requirepass" configuration
101
+ # directive below) it is possible to tell the slave to authenticate before
102
+ # starting the replication synchronization process, otherwise the master will
103
+ # refuse the slave request.
104
+ #
105
+ # masterauth <master-password>
106
+
107
+ ################################## SECURITY ###################################
108
+
109
+ # Require clients to issue AUTH <PASSWORD> before processing any other
110
+ # commands. This might be useful in environments in which you do not trust
111
+ # others with access to the host running redis-server.
112
+ #
113
+ # This should stay commented out for backward compatibility and because most
114
+ # people do not need auth (e.g. they run their own servers).
115
+ #
116
+ # Warning: since Redis is pretty fast an outside user can try up to
117
+ # 150k passwords per second against a good box. This means that you should
118
+ # use a very strong password otherwise it will be very easy to break.
119
+ #
120
+ # requirepass foobared
121
+
122
+ ################################### LIMITS ####################################
123
+
124
+ # Set the max number of connected clients at the same time. By default there
125
+ # is no limit, and it's up to the number of file descriptors the Redis process
126
+ # is able to open. The special value '0' means no limits.
127
+ # Once the limit is reached Redis will close all the new connections sending
128
+ # an error 'max number of clients reached'.
129
+ #
130
+ # maxclients 128
131
+
132
+ # Don't use more memory than the specified amount of bytes.
133
+ # When the memory limit is reached Redis will try to remove keys with an
134
+ # EXPIRE set. It will try to start freeing keys that are going to expire
135
+ # in little time and preserve keys with a longer time to live.
136
+ # Redis will also try to remove objects from free lists if possible.
137
+ #
138
+ # If all this fails, Redis will start to reply with errors to commands
139
+ # that will use more memory, like SET, LPUSH, and so on, and will continue
140
+ # to reply to most read-only commands like GET.
141
+ #
142
+ # WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
143
+ # 'state' server or cache, not as a real DB. When Redis is used as a real
144
+ # database the memory usage will grow over the weeks, it will be obvious if
145
+ # it is going to use too much memory in the long run, and you'll have the time
146
+ # to upgrade. With maxmemory after the limit is reached you'll start to get
147
+ # errors for write operations, and this may even lead to DB inconsistency.
148
+ #
149
+ # maxmemory <bytes>
150
+
151
+ ############################## APPEND ONLY MODE ###############################
152
+
153
+ # By default Redis asynchronously dumps the dataset on disk. If you can live
154
+ # with the idea that the latest records will be lost if something like a crash
155
+ # happens this is the preferred way to run Redis. If instead you care a lot
156
+ # about your data and don't want to that a single record can get lost you should
157
+ # enable the append only mode: when this mode is enabled Redis will append
158
+ # every write operation received in the file appendonly.aof. This file will
159
+ # be read on startup in order to rebuild the full dataset in memory.
160
+ #
161
+ # Note that you can have both the async dumps and the append only file if you
162
+ # like (you have to comment the "save" statements above to disable the dumps).
163
+ # Still if append only mode is enabled Redis will load the data from the
164
+ # log file at startup ignoring the dump.rdb file.
165
+ #
166
+ # IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append
167
+ # log file in background when it gets too big.
168
+
169
+ appendonly no
170
+
171
+ # The name of the append only file (default: "appendonly.aof")
172
+ # appendfilename appendonly.aof
173
+
174
+ # The fsync() call tells the Operating System to actually write data on disk
175
+ # instead to wait for more data in the output buffer. Some OS will really flush
176
+ # data on disk, some other OS will just try to do it ASAP.
177
+ #
178
+ # Redis supports three different modes:
179
+ #
180
+ # no: don't fsync, just let the OS flush the data when it wants. Faster.
181
+ # always: fsync after every write to the append only log . Slow, Safest.
182
+ # everysec: fsync only if one second passed since the last fsync. Compromise.
183
+ #
184
+ # The default is "everysec" that's usually the right compromise between
185
+ # speed and data safety. It's up to you to understand if you can relax this to
186
+ # "no" that will will let the operating system flush the output buffer when
187
+ # it wants, for better performances (but if you can live with the idea of
188
+ # some data loss consider the default persistence mode that's snapshotting),
189
+ # or on the contrary, use "always" that's very slow but a bit safer than
190
+ # everysec.
191
+ #
192
+ # If unsure, use "everysec".
193
+
194
+ # appendfsync always
195
+ appendfsync everysec
196
+ # appendfsync no
197
+
198
+ ################################ VIRTUAL MEMORY ###############################
199
+
200
+ # Virtual Memory allows Redis to work with datasets bigger than the actual
201
+ # amount of RAM needed to hold the whole dataset in memory.
202
+ # In order to do so very used keys are taken in memory while the other keys
203
+ # are swapped into a swap file, similarly to what operating systems do
204
+ # with memory pages.
205
+ #
206
+ # To enable VM just set 'vm-enabled' to yes, and set the following three
207
+ # VM parameters accordingly to your needs.
208
+
209
+ vm-enabled no
210
+ # vm-enabled yes
211
+
212
+ # This is the path of the Redis swap file. As you can guess, swap files
213
+ # can't be shared by different Redis instances, so make sure to use a swap
214
+ # file for every redis process you are running. Redis will complain if the
215
+ # swap file is already in use.
216
+ #
217
+ # The best kind of storage for the Redis swap file (that's accessed at random)
218
+ # is a Solid State Disk (SSD).
219
+ #
220
+ # *** WARNING *** if you are using a shared hosting the default of putting
221
+ # the swap file under /tmp is not secure. Create a dir with access granted
222
+ # only to Redis user and configure Redis to create the swap file there.
223
+ vm-swap-file /tmp/redis.swap
224
+
225
+ # vm-max-memory configures the VM to use at max the specified amount of
226
+ # RAM. Everything that deos not fit will be swapped on disk *if* possible, that
227
+ # is, if there is still enough contiguous space in the swap file.
228
+ #
229
+ # With vm-max-memory 0 the system will swap everything it can. Not a good
230
+ # default, just specify the max amount of RAM you can in bytes, but it's
231
+ # better to leave some margin. For instance specify an amount of RAM
232
+ # that's more or less between 60 and 80% of your free RAM.
233
+ vm-max-memory 0
234
+
235
+ # Redis swap files is split into pages. An object can be saved using multiple
236
+ # contiguous pages, but pages can't be shared between different objects.
237
+ # So if your page is too big, small objects swapped out on disk will waste
238
+ # a lot of space. If you page is too small, there is less space in the swap
239
+ # file (assuming you configured the same number of total swap file pages).
240
+ #
241
+ # If you use a lot of small objects, use a page size of 64 or 32 bytes.
242
+ # If you use a lot of big objects, use a bigger page size.
243
+ # If unsure, use the default :)
244
+ vm-page-size 32
245
+
246
+ # Number of total memory pages in the swap file.
247
+ # Given that the page table (a bitmap of free/used pages) is taken in memory,
248
+ # every 8 pages on disk will consume 1 byte of RAM.
249
+ #
250
+ # The total swap size is vm-page-size * vm-pages
251
+ #
252
+ # With the default of 32-bytes memory pages and 134217728 pages Redis will
253
+ # use a 4 GB swap file, that will use 16 MB of RAM for the page table.
254
+ #
255
+ # It's better to use the smallest acceptable value for your application,
256
+ # but the default is large in order to work in most conditions.
257
+ vm-pages 134217728
258
+
259
+ # Max number of VM I/O threads running at the same time.
260
+ # This threads are used to read/write data from/to swap file, since they
261
+ # also encode and decode objects from disk to memory or the reverse, a bigger
262
+ # number of threads can help with big objects even if they can't help with
263
+ # I/O itself as the physical device may not be able to couple with many
264
+ # reads/writes operations at the same time.
265
+ #
266
+ # The special value of 0 turn off threaded I/O and enables the blocking
267
+ # Virtual Memory implementation.
268
+ vm-max-threads 4
269
+
270
+ ############################### ADVANCED CONFIG ###############################
271
+
272
+ # Glue small output buffers together in order to send small replies in a
273
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
274
+ # in terms of number of queries per second. Use 'yes' if unsure.
275
+ glueoutputbuf yes
276
+
277
+ # Hashes are encoded in a special way (much more memory efficient) when they
278
+ # have at max a given numer of elements, and the biggest element does not
279
+ # exceed a given threshold. You can configure this limits with the following
280
+ # configuration directives.
281
+ hash-max-zipmap-entries 64
282
+ hash-max-zipmap-value 512
283
+
284
+ # Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
285
+ # order to help rehashing the main Redis hash table (the one mapping top-level
286
+ # keys to values). The hash table implementation redis uses (see dict.c)
287
+ # performs a lazy rehashing: the more operation you run into an hash table
288
+ # that is rhashing, the more rehashing "steps" are performed, so if the
289
+ # server is idle the rehashing is never complete and some more memory is used
290
+ # by the hash table.
291
+ #
292
+ # The default is to use this millisecond 10 times every second in order to
293
+ # active rehashing the main dictionaries, freeing memory when possible.
294
+ #
295
+ # If unsure:
296
+ # use "activerehashing no" if you have hard latency requirements and it is
297
+ # not a good thing in your environment that Redis can reply form time to time
298
+ # to queries with 2 milliseconds delay.
299
+ #
300
+ # use "activerehashing yes" if you don't have such hard requirements but
301
+ # want to free memory asap when possible.
302
+ activerehashing yes
303
+
304
+ ################################## INCLUDES ###################################
305
+
306
+ # Include one or more other config files here. This is useful if you
307
+ # have a standard template that goes to all redis server but also need
308
+ # to customize a few per-server settings. Include files can include
309
+ # other files, so use this wisely.
310
+ #
311
+ # include /path/to/local.conf
312
+ # include /path/to/other.conf