下午我给 statlysis.gem 增加了对 sum 的支持 。主题的解决方案如下:
第一步,数据准备:
class Mxx; include Mongoid::Document; field :col_sum, :type => Float; end
class Mxx
before_save do
self.col_sum = self.col_a * self.col_b
end
end
第二步,配置统计:
Statlysis.setup do
daily Mxx, :sum_columns => [:col_sum]
end
第三步,统计和察看结果:
cron = Statlysis.daily['mxx'].first => #<Statlysis::Timely:0x7f891cc9db30 @source_type=:mongoid, @time_column=:created_at, @time_unit=:day, @time_zone=#<ActiveSupport::TimeZone:0x7f891b4783e8>, @multiple_dataset=#<Statlysis::MongoidDataset:0x7f891cca2338>, @sum_columns=#<Array:0x7f891cc9fd18>, @stat_table_name="timely_mxxes_d", @stat_model=#<Class:0x7f8920966918>>
cron.stat_model # => TimelyMxxesD
cron.run
# 统计结果类似于
cron.output[1] # => {:t=>Fri, 14 Dec 2012 00:00:00 +0800, :timely_c=>11, :totally_c=>16, :timely_favcount_s=>24.0, :totally_favcount_s=>38.0}
然后显示的时候从统计表 timely_mxxes_d 抽取就可以了,平均数,中位数等都可以从里面算出来。
欢迎报告 BUG 或功能改进:)
建议使用 https://github.com/eoecn/statlysis 这个面向 ORM 统计的 Ruby DSL,具体见 README,比这样复杂地拼 SQL 好理解多了。
我看到你这里需要对两个字段做额外计算,建议也是预先在事务里写入到该表其他字段为好。
补: 抱歉没看到 SQL 里有 SUM,过段时间给出解决方案:)
真建议做个网站,把每家公司技术方面的面试流程和特点都爆出来,然后大家一一去'调戏'吧
试试这个 Rack 插件:https://github.com/singlebrook/utf8-cleaner/
4, 公司本身就倡导开源,比如 github
从你的说明来看,我把过程分为两个步骤,
其一是收集,日志以 CSV 格式写入,而不是数据库,可能是应用程序为了写入性能的考虑。
其二是分析数据的清理和初始化,上面你提到为了时间和性能上的考虑,你是想把它们全部读入内存来提升访问速度以此来加快计算的。
但是这里的“全部读入内存”我觉得是不可取的,尤其是要”大量查询“和“性能”,我觉得应该存在为数据索引而生的数据库里(推荐支持 MapReduce 的 Mongodb,或者专门为统计分析优化的列式数据库),并尽量缓存部分计算结果在磁盘上是比较可取的自然的一个方案。(如果你需要实时统计等其他需求就别论了)。
另外推荐我写的一个基于 Ruby DSL 的统计分析解决方案,地址在 https://github.com/eoecn/statlysis ,它也支持多表的数据查询统计。目前在开发第二版,欢迎使用和完善:)
CSV 是一个很规范的数据格式,mysql 和 mongodb 等数据库是直接支持导入的,不必再解析然后通过 ORM 导入数据库。
如果只是简单的 count,而且这几个 collection 要统计的数据结构都是一致的,推荐使用我正在开发的面向 ActiveRecord 和 Mongoid 统计分析的 gem 包 statlysis,项目地址在:https://github.com/eoecn/statlysis
使用方法如下:
批量初始化 model 和表结构
{'07' => 1..31, '08' => 1..12}.map do |month, day_range|
day_range.map do |day|
# define model dynamically, e.g. MultipleLog20130729
date_str = "2013#{month}#{day.to_s.rjust(2, '0')}"
collection_class_name = "MultipleLog#{date_str}"
collection_name = collection_class_name.sub("MultipleLog", "multiple_log_")
eval("
class #{collection_class_name}
include Mongoid::Document
self.default_collection_name = #{collection_name.to_json}
field :t, :type => DateTime
field :url, :type => String
index({t: -1}, {:background => true})
end
")
end
end
简单的配置
Statlysis.setup do
set_database :statlysis
daily Mongoid[/eoe_logs_[0-9]+$/].where(:ui => {"$ne" => 0}), :time_column => :t
end
访问和统计
[23] pry(#<Statlysis::Configuration>)> Statlysis.daily['multi'].first
=> #<Statlysis::Timely:0x7fb9cc60a490 @is_activerecord=#<FalseClass:0x0>, @is_mongoid=#<TrueClass:0x4>, @is_orm=#<TrueClass:0x4>, @time_column=:t, @time_unit=:day, @time_zone=#<NilClass:0x8>, @multiple_dataset=#<Statlysis::MongoidDataset:0x7fb9cc67e840>, @stat_table_name="timely_multiplelog_d", @stat_model=#<Class:0x7fb9cc6116c8>, @output=#<Array:0x7fb9cc798118>>
[24] pry(#<Statlysis::Configuration>)> Statlysis.daily['multi'].first.output
=> [{:t=>Mon, 01 Jul 2013 00:00:00 +0000, :timely_c=>1, :totally_c=>1},
{:t=>Tue, 02 Jul 2013 00:00:00 +0000, :timely_c=>2, :totally_c=>3},
{:t=>Wed, 03 Jul 2013 00:00:00 +0000, :timely_c=>3, :totally_c=>6},
{:t=>Thu, 04 Jul 2013 00:00:00 +0000, :timely_c=>4, :totally_c=>10},
{:t=>Fri, 05 Jul 2013 00:00:00 +0000, :timely_c=>5, :totally_c=>15},
{:t=>Sat, 06 Jul 2013 00:00:00 +0000, :timely_c=>6, :totally_c=>21},
{:t=>Sun, 07 Jul 2013 00:00:00 +0000, :timely_c=>7, :totally_c=>28},
{:t=>Mon, 08 Jul 2013 00:00:00 +0000, :timely_c=>8, :totally_c=>36},
{:t=>Tue, 09 Jul 2013 00:00:00 +0000, :timely_c=>9, :totally_c=>45},
{:t=>Wed, 10 Jul 2013 00:00:00 +0000, :timely_c=>10, :totally_c=>55},
{:t=>Thu, 11 Jul 2013 00:00:00 +0000, :timely_c=>11, :totally_c=>66},
{:t=>Fri, 12 Jul 2013 00:00:00 +0000, :timely_c=>12, :totally_c=>78},
{:t=>Sat, 13 Jul 2013 00:00:00 +0000, :timely_c=>13, :totally_c=>91},
{:t=>Sun, 14 Jul 2013 00:00:00 +0000, :timely_c=>14, :totally_c=>105},
{:t=>Mon, 15 Jul 2013 00:00:00 +0000, :timely_c=>15, :totally_c=>120},
{:t=>Tue, 16 Jul 2013 00:00:00 +0000, :timely_c=>16, :totally_c=>136},
{:t=>Wed, 17 Jul 2013 00:00:00 +0000, :timely_c=>17, :totally_c=>153},
{:t=>Thu, 18 Jul 2013 00:00:00 +0000, :timely_c=>18, :totally_c=>171},
{:t=>Fri, 19 Jul 2013 00:00:00 +0000, :timely_c=>19, :totally_c=>190},
{:t=>Sat, 20 Jul 2013 00:00:00 +0000, :timely_c=>20, :totally_c=>210},
{:t=>Sun, 21 Jul 2013 00:00:00 +0000, :timely_c=>21, :totally_c=>231},
{:t=>Mon, 22 Jul 2013 00:00:00 +0000, :timely_c=>22, :totally_c=>253},
{:t=>Tue, 23 Jul 2013 00:00:00 +0000, :timely_c=>23, :totally_c=>276},
{:t=>Wed, 24 Jul 2013 00:00:00 +0000, :timely_c=>24, :totally_c=>300},
{:t=>Thu, 25 Jul 2013 00:00:00 +0000, :timely_c=>25, :totally_c=>325},
{:t=>Fri, 26 Jul 2013 00:00:00 +0000, :timely_c=>26, :totally_c=>351},
{:t=>Sat, 27 Jul 2013 00:00:00 +0000, :timely_c=>27, :totally_c=>378},
{:t=>Sun, 28 Jul 2013 00:00:00 +0000, :timely_c=>28, :totally_c=>406},
{:t=>Mon, 29 Jul 2013 00:00:00 +0000, :timely_c=>29, :totally_c=>435},
{:t=>Tue, 30 Jul 2013 00:00:00 +0000, :timely_c=>30, :totally_c=>465},
{:t=>Wed, 31 Jul 2013 00:00:00 +0800, :timely_c=>27, :totally_c=>483}]
[25] pry(#<Statlysis::Configuration>)>
官网上线后第一时间报名!
工程师文化在整个产业里太小众,再加上中国是世界工厂,催生不了那么多技术人才。
_.keys(eoe) // ["domain_to_urls", "domain", "app", "uid", "uname", "uhash", "avatar", "homeUrl", "appUrl", "app_item", "app_item_id", "visitor_list_pattern", "fp", "jsfun_user_avatar_url", "is_uid_a_teacher", "utils", "faye_port", "learn_summary_data", "is_local", "current_user", "is_uid_uhash_valid", "course", "all_classes", "teachers", "is_a_teacher", "current_class", "is_current_class_time_end", "period_id", "students", "is_a_student", "lessons", "lesson_id_to_seqs", "current_issue", "is_current_issue_finished", "current_lesson_time_racings", "class_channel", "lesson_channel", "lesson", "uid_to_unames", "section_with_exam", "online_uids", "user", "issue", "spend_seconds", "is_not_finished_issue", "lesson_to_spend_time", "lessons_seq_in_students", "lesson_to_questions_count", "lesson_to_answers_count", "learn_id_to_exam_count", "students_in_summary_unfinished", "students_in_summary_finished_sort", "seq_in_class", "learn_summary", "feedback", "is_debug", "faye"]
_.keys(eoe).length // 59
_.reject(eoe, function(s) { return _.isFunction(s); }).length // 49
在 Chrome 控制台可以看到的有 49 个变量数据输出,如何管理是个大问题,里面还包括读写和前后依赖,目前我想到的解决办法是分到不同的流程里面。
来个接近自然语言一点的,也是我之前做数据展示时用的技巧。
require 'date'
require 'active_support/all'
date_to_count_hash = Hash[ (Date.parse("2013-6-30")..Date.parse("2013-07-07")).to_a.map {|i| [i, 0] } ]
[["2013-07-05", 12], ["2013-07-01", 24], ["2013-06-30", 34]].each {|date_str, count| date_to_count_hash[Date.parse(date_str)] = count }
date_to_count_hash.map(&:last)
Array 也好,或者时间对应数据的 Hash(Ruby 1.9 的 Hash 是按插入顺序排序的) 也好,缺失的值都是必须显示声明的,不管是 0 还是 空值 nil。
之前我写过一篇 Android 优亿市场数据采集分析系统概要 ,有个技巧是 统计数据存储和展示应该是分开的,特别是涉及到多维时有很多空值的情况。希望能对你有所帮助:)
@coolesting 我猜测你要实现的需求是实现变量的作用域动态配置,而不用作为一般的方法参数传入。
在 Ruby 里,局部变量 (local variable) 只能在 method 和 loop 内被访问,实例变量 (instance variable) 可以在一个类的实例的方法之间互访。
所以要么和 @guyanbiao 说的一样,把 i
这个变量拎到外面。
或者用 实例变量 也可以实现,如下:
1.9.3p392 :001 > class HH; def initialize &blk; @i = 5; instance_eval &blk; end; end
=> nil
1.9.3p392 :002 > HH.new { puts (@i + 5) }
10
=> #<HH:0x000001010588e8 @i=5>
1.9.3p392 :003 > @i
=> nil
1.9.3p392 :004 >
关于 Ruby 里的各种变量的用途在 http://www.techotopia.com/index.php/Ruby_Variable_Scope 这里解释的比较清楚了,包括类变量等。
https://www.ruby-toolbox.com/categories/rails_admin_interfaces 看下这个 gem 分类
RailsAdmin ActiveAdmin
使用
self.formats = [:html]
@paginate_html = render_to_string(:partial => "qa/paginate")
self.formats = [:json]
进行切换即可。
可以参考这里 https://github.com/eoecn/qa-rails/blob/master/app/controllers/qa_controller.rb#L15
业务流程化,技术模块化。不管是是业务逻辑还是技术逻辑,尽量作成 DSL,这样技术的人看到的技术,业务的人看到的是业务。
上面这些可以考虑和 devise 一样,作成一个模块插件。
更新不能,昨天的包了
curl -I http://ruby.taobao.org/quick/Marshal.4.8/rack_image_assets_cache_control-0.2.gemspec.rz
HTTP/1.1 404 Not Found
Server: nginx/1.1.6
Date: Wed, 08 May 2013 02:16:15 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
curl -I http://rubygems.org/quick/Marshal.4.8/rack_image_assets_cache_control-0.2.gemspec.rz
HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Wed, 08 May 2013 02:16:25 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
Location: http://tokyo-m.rubygems.org/quick/Marshal.4.8/rack_image_assets_cache_control-0.2.gemspec.rz
#3 楼 @saiga rabl 我尝试过很不好用,很诡异的 API(上一次用是两年前,现在全然忘记了需要重新学习)。as_json 可以更让接口更面向 RESTful 设计,没有思维切换过程。
ruby
format.json { render :json => {:topic => @topic, :replies => @topic.replies}, :status => 200}
里面对应的 topic 和 reply 的 JSON 格式在各自的 model 里定义就可以了,重载或覆盖。ruby
format.json { render :json => {:topics => @topics, :paginate_html => @paginate_html}, :status => 200}
我觉得 Rails 自带的 as_json 很不错了。有问题的话,那很大程度上是数据库没设计好。
#6 楼 @hpyhacking 我从《Ruby 元编程》里学到的最大的体会就是:class, module, def, proc, lambda 等都是定义作用域的思想确实让人耳目一新。
多表查询效率太低,建议用 text 字段代替,然后用 JSON 序列和反序列化
推荐用 https://github.com/bdurand/json_record,操作封装的很好了,比如:
class Post < ActiveRecord::Base
serialize_to_json(:json_data) do |schema|
schema.key :title, :required => true
schema.key :body, :required => true
schema.key :author, Person, :required => true
schema.many :comments, Comment
end
end