实现一个有效的类似slack的子域名建议

时间:2016-04-13 13:05:32

标签: ruby-on-rails ruby postgresql

我有一个带PostgreSQL的Rails应用程序。

如果已经选择了用户输入,我正在尝试实现一种方法来为某个资源建议替代名称。

我的参考是松懈的:

slack domain input

是否有任何解决方案可以有效地做到这一点?

为了有效我的意思是:使用只有一个一小组查询。但是,纯SQL解决方案会很棒。

我的初步实施如下:

def generate_alternative_names(model, column_name, count)
  words = model[column_name].split(/[,\s\-_]+/).reject(&:blank?)
  candidates = 100.times.map! { |i| generate_candidates_using_a_certain_strategy(i, words) }
  already_used = model.class.where(column_name => candidates).pluck(column_name)
  (candidates - already_used).first(count)
end

# Usage example:
model = Domain.new
model.name = 'hello-world'
generate_alternative_names(model, :name, 5)
# => ["hello_world", "hello-world2", "world_hello", ...]

它会生成100个候选项,然后检查数据库中的匹配项并将其从候选项列表中删除。最后,它返回提取的第一个count值。

此方法是尽力而为的实施,因为它适用于少量冲突(在我的情况下,100次冲突)的小型建议集。

即使我增加这个幻数(100),也不会无限缩放。

您是否知道一种改进此方法的方法,因此它可以针对大量冲突进行扩展而不使用幻数?

1 个答案:

答案 0 :(得分:2)

我会采用相反的方法:使用LIKE在数据库中查询现有记录,然后生成已跳过的建议:

def alternatives(model, column, word, count)
  taken = model.class.where("#{column} LIKE '%#{word}%'").pluck(column)
  count.times.map! do |i|
    generate_candidates_using_a_certain_strategy(i, taken)
  end
end

generate_candidates_using_a_certain_strategy接收要跳过的已取词数组。在两个具有相同名称的请求中可能存在一个可能存在竞争条件的故障,但我认为这不会导致任何问题,因为当实际创建失败时,您总是可以自由地道歉。