require 'csv' require 'redis/connection/hiredis' require 'redis' require 'logger' require 'open-uri' class Earthquakes attr_accessor :id_set, :region_set, :magnitude_set attr_accessor :magnitude_scores_set, :data_url def initialize @redis = Redis.new @id_set = 'earthquake-ids' @region_set = 'earthquake-regions' @magnitude_set = 'earthquake-magnitudes' @magnitude_scores_set = 'earthquakes-magnitudes-scores' @data_url = 'http://earthquake.usgs.gov/earthquakes/catalogs/eqs7day-M1.txt' @logger = Logger.new(STDOUT) @logger.formatter = proc do |severity, datetime, progname, msg| "#{datetime}: #{msg}\n" end end def get_info(earthquake_id) @redis.hgetall(with_prefix(earthquake_id, 'eqid')) end def in_region(region) @redis.smembers(with_prefix(region, 'eqregion')) end def with_magnitude_in_range(min_magnitude, max_magnitude) min_mag, max_mag = magnitude_as_int(min_magnitude), magnitude_as_int(max_magnitude) @logger.debug( "Fetching magnitudes with scores in range #{min_mag}-#{max_mag}") @redis.zrange(@magnitude_scores_set, min_mag, max_mag) end def all_ids @redis.smembers(@id_set).map { |i| sans_prefix(i, 'eqid') } end def all_regions @redis.smembers(@region_set).map { |r| sans_prefix(r, 'eqregion') } end def all_magnitudes @redis.smembers(@magnitude_set).map { |m| sans_prefix(m, 'eqmagnitude') } end def drop_all @logger.info('Removing data for each earthquake') all_ids.each do |i| @logger.info("Removing data for earthquake #{sans_prefix(i, 'eqid')}") @redis.del(i) end @logger.info('Removing earthquake id set') @redis.del(@id_set) @logger.info('Removing earthquake region set') @redis.del(@region_set) @logger.info('Removing earthquake magnitude set') @redis.del(@magnitude_set) @logger.info('Removing earthquake magnitude scores set') @redis.del(@magnitude_scores_set) end def load_data data = CSV.parse( open(@data_url).read, :headers => true, :header_converters => [:symbol] ) data.each do |row| @logger.info("Adding earthquake #{row[:eqid]}") load_one_row(row) end end private def load_one_row(row) @redis.multi do |redis_multi| id_key = with_prefix(row[:eqid].downcase, 'eqid') load_id_and_attrs_for_row(row, id_key, redis_multi) load_region_for_row(row, id_key, redis_multi) load_magnitude_for_row(row, id_key, redis_multi) end end def load_id_and_attrs_for_row(row, id_key, redis_multi) redis_multi.sadd(@id_set, id_key) row.headers.each do |header| redis_multi.hset(id_key, header.downcase, row[header].downcase) end end def load_region_for_row(row, id_key, redis_multi) region_key = with_prefix(row[:region].downcase, 'eqregion') redis_multi.sadd(region_key, id_key) redis_multi.sadd(@region_set, region_key) end def load_magnitude_for_row(row, id_key, redis_multi) magnitude_key = with_prefix(row[:magnitude], 'eqmagnitude') redis_multi.sadd(magnitude_key, id_key) redis_multi.sadd(@magnitude_set, magnitude_key) score = magnitude_as_int(row[:magnitude]) @logger.info("Setting score of #{score} for row #{row.inspect}") redis_multi.zadd(@magnitude_scores_set, score, id_key) end def with_prefix(key, prefix) if not /^#{prefix}:/.match(key) return "#{prefix}:#{key}" end key end def sans_prefix(key, prefix) key.gsub(/^#{prefix}:/, '') end def magnitude_as_int(magnitude) magnitude.to_s.gsub(/\./, '').to_i end end if $0 == __FILE__ Earthquakes.new.send(ARGV.first) end