serialize и собственный формат хранения

1 view
Skip to first unread message

Max Lapshin

unread,
Nov 20, 2008, 4:05:36 AM11/20/08
to RubyOnRails to russian
У меня такая ситуация: очень много где для кеширования в строку модели складываются ID.
Например в событии список идущих людей. Сейчас это делается с помощью serialize, который
упорно пишет в yaml.

Есть мысль перевести это всё на формат id1,id2,id3, который читается гораздо быстрее ямля
и гораздо проще формировать БД ( group_concat(id separator ',')).

Я поглядел в сырцы ActiveRecord-а: подхачить serialize, что бы ему можно было бы указывать
схему десериализации можно, но немножко беспокойно.

Кто-нибудь встречал подобные наработки? Я в гугле по запросу «rails serialize change format»  ничего не нашел =(

Oleg Andreev

unread,
Nov 20, 2008, 7:14:16 AM11/20/08
to ror...@googlegroups.com

On 20.11.2008, at 12:05, Max Lapshin wrote:

>
> Я поглядел в сырцы ActiveRecord-а: подхачить
> serialize, что бы ему можно было бы
> указывать
> схему десериализации можно, но
> немножко беспокойно.
>
> Кто-нибудь встречал подобные
> наработки? Я в гугле по запросу «rails
> serialize change format» ничего не нашел =(

Рискуя услышать старую шарманку про
"бизнес-продукты", скромно доложу, что в
датамаппере использую кустомные
DataMapper::Types, которые решают именно эту
проблему: кустомную сериализацию
всего чего угодно.

В твоем случае рекомендую определить
#field и #field=, которые делают attribute_read,
attribute_write с необходимой конвертацией.

Max Lapshin

unread,
Nov 20, 2008, 7:44:00 AM11/20/08
to ror...@googlegroups.com
Проблема во write_attribute и read_attribute, которые всё ломают.
Отсутствие в AR нормального пользовательского маппинга типов раздражает ппц как. Например,
сохранять рубли с копейками в сотнях копеек в int сложно именно из-за этой дури.


faust45

unread,
Nov 20, 2008, 8:05:58 AM11/20/08
to RubyOnRails to russian
А какже compose_of?
Разве он в етом случае не подходит?

compose_of :money, %w(to_i to_копеек) do |value|
Money.new(value)
end

class Money
to_копейки
end

Oleg...@gmail.com

unread,
Nov 20, 2008, 8:16:51 AM11/20/08
to RubyOnRails to russian

On 20 нояб, 16:05, faust45 <faus...@mail.zp.ua> wrote:
> А какже compose_of?
> Разве он в етом случае не подходит?
>
> compose_of :money, %w(to_i to_копеек) do |value|
>   Money.new(value)
> end
>
> class Money
>   to_копейки
> end
>

Да, это оно самое. Позор мне. Только composed_of, а не compose_of.

Исчерпывающие примеры:
http://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html

Max Lapshin

unread,
Nov 20, 2008, 8:24:08 AM11/20/08
to ror...@googlegroups.com
Честно говоря, я смутно понимаю, как это мне поможет.
У меня в базе записано:

id |  visitor_ids
1  |  234,3254,564,13,536,5

Я хочу, что бы было так:

> Event.find(:first)
# => #<Event id:1 visitor_ids: [234, 3254, 564, 13, 536, 5]>

При этом visitor_ids — не прокси объект, а массив.

faust45

unread,
Nov 20, 2008, 8:39:20 AM11/20/08
to RubyOnRails to russian
Может так можно


class Decorator < Array
def initialize(ids)
super
@ids =
case ids
when String
self[0...0] = ids.split(',').map(&:to_i)
end

def to_s
@ids.join(',')
end
end

только етот обект его нельзя будет модифицировать
ето ещё можно посмотреть
http://github.com/Fingertips/attribute-decorator/tree/master

On 20 нояб, 08:24, "Max Lapshin" <max.laps...@gmail.com> wrote:
> Честно говоря, я смутно понимаю, как это мне поможет.
> У меня в базе записано:
>
> id | visitor_ids
> 1 | 234,3254,564,13,536,5
>
> Я хочу, что бы было так:
>
> > Event.find(:first)
>
> # => #<Event id:1 visitor_ids: [234, 3254, 564, 13, 536, 5]>
>

> При этом visitor_ids -- не прокси объект, а массив.

Max Lapshin

unread,
Nov 20, 2008, 8:41:06 AM11/20/08
to ror...@googlegroups.com
Ну  я понял. Это все несерьезно. Рельсы навязывают этот проклятый ямль в качестве формата сериализации, значит буду с этим бороться.

faust45

unread,
Nov 20, 2008, 8:51:53 AM11/20/08
to RubyOnRails to russian
Да кстате а нельзя указать serialize :attribute, Decorator
и Decorator to_yaml переопределить?

Max Lapshin

unread,
Nov 20, 2008, 9:17:10 AM11/20/08
to ror...@googlegroups.com
Нет. Этот класс используется только для эмулирования жесткой типизации.

В attributes_with_quotes идет такое:

            # We need explicit to_yaml because quote() does not properly convert Time/Date fields to YAML.
            if value && self.class.serialized_attributes.has_key?(name) && (value.acts_like?(:date) || value.acts_like?(:time))
              value = value.to_yaml
            end


а в   unserialize_attribute(attr_name) идет:

      unserialized_object = object_from_yaml(@attributes[attr_name])


Поэтому надо жестко хачить эти методы, что бы они человечески работали.

Oleg Andreev

unread,
Nov 20, 2008, 9:55:46 AM11/20/08
to ror...@googlegroups.com

On 20.11.2008, at 12:05, Max Lapshin wrote:

> У меня такая ситуация: очень много где
> для кеширования в строку модели
> складываются ID.
> Например в событии список идущих
> людей. Сейчас это делается с помощью
> serialize, который
> упорно пишет в yaml.

Почему бы не кешировать список идущих
людей в мемкеше? Не говоря уже о том,
что индекс по [:event_id, :person_id] в EventMembership
сам по себе очень эффективен.

Max Lapshin

unread,
Nov 20, 2008, 9:59:12 AM11/20/08
to ror...@googlegroups.com
Эта штука оказалась удобнее чем мемкешд и существенно быстрее, чем лишний селект из базы.

Особенно на конструкции, когда у меня есть список моих друзей и список из, скажем, 10 событий и
надо показывать сколько из моих друзей идет на каждое событие.

Oleg Andreev

unread,
Nov 20, 2008, 10:14:10 AM11/20/08
to ror...@googlegroups.com
On 20.11.2008, at 17:59, Max Lapshin wrote:

> Эта штука оказалась удобнее чем
> мемкешд и существенно быстрее, чем
> лишний селект из базы.

Про селект понятно. А про мемкешд
непонятно, чем неудобно. "Просто добавь
воды":

class Event
has_many :memberships, :class_name => "EventMembership"
def member_ids
CACHE["Event#{id}.member_ids"] ||= memberships.map{|m| m.person_id}
end
end

class EventMembership
belongs_to :event
belongs_to :person
end


Max Lapshin

unread,
Nov 20, 2008, 10:18:11 AM11/20/08
to ror...@googlegroups.com
Да неудобно тем, что это инвалидировать надо и разогревать. А в базе уже разогретый кеш получается.

Oleg...@gmail.com

unread,
Nov 20, 2008, 10:18:17 AM11/20/08
to RubyOnRails to russian


class EventMembership
...
after_create :clear_event_member_ids_cache

def clear_event_member_ids_cache
CACHE["Event#{event_id}.member_ids"] = nil
end
end


Max Lapshin

unread,
Nov 20, 2008, 10:19:42 AM11/20/08
to ror...@googlegroups.com




class EventMembership
  ...
 after_create :clear_event_member_ids_cache

 def clear_event_member_ids_cache
   CACHE["Event#{event_id}.member_ids"] = nil
 end
end


Тогда уж лучше его предзаполнять, что бы лагов было меньше.


Oleg Andreev

unread,
Nov 20, 2008, 10:20:07 AM11/20/08
to ror...@googlegroups.com
По-моему, ты просто решаешь проблему
кеша не в том месте. Это, конечно, не
оправдывает корявость кустомных типов
в AR, но я бы кеш держал логически
отдельно от кошерных атрибутов.



Max Lapshin

unread,
Nov 20, 2008, 10:22:42 AM11/20/08
to ror...@googlegroups.com


2008/11/20 Oleg Andreev <oleg...@gmail.com>


По-моему, ты просто решаешь проблему
кеша не в том месте. Это, конечно, не
оправдывает корявость кустомных типов
в AR, но я бы кеш держал логически
отдельно от кошерных атрибутов.

Ты неправ. Не «не оправдывает корявость кустомных типов», а «не оправдывает ничем не объяснимое
полное отсутствие кустомных типов» =)


Oleg Andreev

unread,
Nov 20, 2008, 10:24:26 AM11/20/08
to ror...@googlegroups.com

On 20.11.2008, at 18:22, Max Lapshin wrote:

> Ты неправ. Не «не оправдывает
> корявость кустомных типов», а «не
> оправдывает ничем не объяснимое
> полное отсутствие кустомных типов» =)

Не-а. Есть же composed_of =) Впрочем, хоть
горшком назови.

Oleg Andreev

unread,
Nov 20, 2008, 10:26:56 AM11/20/08
to ror...@googlegroups.com

On 20.11.2008, at 18:19, Max Lapshin wrote:

> Тогда уж лучше его предзаполнять, что
> бы лагов было меньше.

Кстати не факт. Ты будешь делать тот же
самый запрос, только вопрос в том, в
какой момент: сразу после изменения
списка, или первый раз, когда кому-то
понадобится этот массив. В
высоконагруженной системе разница
между этими событиями очень небольшая,
любое из двух решений не отменяет
борьбы с race conditions в кеше, а
предзаполнение лишний раз напрягает
мозги читателя кода.

Я бы не делал лишних движений.




Max Lapshin

unread,
Nov 20, 2008, 10:29:04 AM11/20/08
to ror...@googlegroups.com
У меня проблема не с сотней тысяч запросов в секунду, а с тем, что бы пользователю все страницы побыстрее отдавались.

Oleg Andreev

unread,
Nov 20, 2008, 10:30:14 AM11/20/08
to ror...@googlegroups.com
Разницы в скорости не будет,
заполняешь ты массив заранее или нет.
Если, конечно, у тебя не такая ситуация,
что страница ооочень медленно
грузится первый раз, а второй раз ее за
полгода никто не посетит.


julik

unread,
Nov 20, 2008, 12:19:41 PM11/20/08
to ror...@googlegroups.com

On Nov 20, 2008, at 10:05 AM, Max Lapshin wrote:

> Сейчас это делается с помощью serialize,
> который
> упорно пишет в yaml.

Сделать свой наследник или декоратор
Array и переписать ему to_yaml как
self.join(", ")

Sergey Kojin

unread,
Nov 20, 2008, 1:42:12 PM11/20/08
to RubyOnRails to russian
так еще и обратную операцию надо, там там не так все красиво
получается
Reply all
Reply to author
Forward
0 new messages