2016-06-15 3 views
0

У меня есть две таблицы, связанные с отношением habtm (через таблицу).Групповые записи для анализа данных в Rails

Table1 
id : integer 
name: string 

Table2 
id : integer 
name: string 

Table3 
id  : integer 
table1_id: integer 
table2_id: integer 

Мне нужно сгруппировать записи в таблице 1 по близким записям из таблицы2. Пример:

userx = Table1.create() 
user1.table2_ids = 3, 14, 15 
user2.table2_ids = 3, 14, 15, 16 
user3.table2_ids = 3, 14, 16 
user4.table2_ids = 2, 5, 7 
user5.table2_ids = 3, 5 

Результат группирования, что я хочу что-то вроде

=> [ [ [1,2], [3, 14, 15] ], [ [2,3], [3,14, 16] ], [ [ 1, 2, 3, 5], [3] ] ] 

Где первый массив является идентификаторы пользователей вторым является table2_ids. Есть ли какое-нибудь возможное решение SQL или мне нужно создать какой-то алгоритм?

Обновлено: Хорошо, у меня есть код, который работает, как я уже сказал. Может быть, кто-то, кто может мне помочь, сочтет полезным понять мою идею.

def self.compare 
    hash = {} 
    Table1.find_each do |table_record| 
     Table1.find_each do |another_table_record| 
     if table_record != another_table_record 
      results = table_record.table2_ids & another_table_record.table2_ids 
      hash["#{table_record.id}_#{another_table_record.id}"] = results if !results.empty? 
     end 
     end 
    end 
    #hash = hash.delete_if{|k,v| v.empty?} 
    hash.sort_by{|k,v| v.count}.to_h 
    end 

Но я могу поспорить, что вы можете себе представить, сколько времени требуется, чтобы показать мне результат. Для 500 записей Table1 это примерно 1-2 минуты. Если у меня будет больше, время будет увеличено в прогрессии, поэтому мне нужно некоторое элегантное решение или SQL-запрос.

ответ

1
Table1.find_each do |table_record| 
    Table1.find_each do |another_table_record| 
    ... 

Выше коды имеют проблемы с производительностью, которые вы должны запрашивать в базе данных N * N раз, которые можно оптимизировать с помощью одного запроса.

# Query table3, constructing the data useful to us 
# { table1_id: [table2_ids], ... } 
records = Table3.all.group_by { |t| t.table1_id }.map { |t1_id, t3_records| 
    [t1_id, t3_records.map(&:table2_id)] 
    }.to_h 

Тогда вы могли бы сделать то же самое records, чтобы получить конечный результат хэш.

UPDATE:

@AKovtunov вы пропустите меня поняли. Мой код - это первый шаг. С records, которые имеют {t1_id: t2_ids} хэш, вы могли бы сделать что-н, как это:

hash = {} 
records.each do |t1_id, t2_ids| 
    records.each do |tt1_id, tt2_ids| 
    if t1_id != tt1_id 
     inter = t2_ids & tt2_ids 
     hash["#{t1_id}_#{tt1_id}"] = inter if !inter.empty? 
    end 
    end 
end 
+0

Это не то же самое. Ваш код хэширует все как {t1_id: t3_records} И мои аналогичные записи для 2 t1 ids. – AKovtunov

+0

Но работает очень быстро: D – AKovtunov

+0

@AKovtunov Вы пропустили меня поняли. Мой код - это первый шаг. С 'records', которые имеют' {t1_id: t2_ids} 'хэш, вы можете сделать так: hash = {} records.each do | t1_id, t2_ids | records.each do | tt1_id, tt2_ids | if t1_id! = Tt1_id inter = t2_ids & tt2_ids hash ["# {t1_id} _ # {tt1_id}"] = inter if! Inter.empty? конец конец конец –