【问题标题】:How do I put a Ruby function into a SQLite3 query?如何将 Ruby 函数放入 SQLite3 查询中?
【发布时间】:2012-12-18 18:54:36
【问题描述】:

我有一个需要放入 SQLite3 查询的函数。

我有以下方法:

def levenshtein(a, b)
  case
    when a.empty? then b.length
    when b.empty? then a.length
    else [(a[0] == b[0] ? 0 : 1) + levenshtein(a[1..-1], b[1..-1]),
      1 + levenshtein(a[1..-1], b),
      1 + levenshtein(a, b[1..-1])].min
  end
end

我想做一个看起来像这样的查询:

@results = The_db.where('levenshtein("name", ?) < 3', '#{userinput}')

我想在The_db 中找到name 的值,其中name 列的值与用户输入之间的编辑距离小于3。问题是我不知道如何在查询中使用 Ruby 函数。这甚至可能吗?

【问题讨论】:

    标签: ruby-on-rails ruby methods sqlite


    【解决方案1】:

    看看create_function method。您可以使用它来创建这样的自定义函数(您已经定义了 levenshtein Ruby 方法):

    db.create_function "levenshtein", 2 do |func, a, b|
      func.result = levenshtein(a, b)
    end
    

    然后您可以在 SQL 中使用它:

    # first set up some data
    db.execute 'create table names (name varchar(30))'
    %w{Sam Ian Matt John Albert}.each do |n|
      db.execute 'insert into names values (?)', n
    end
    
    #Then use the custom function
    puts db.execute('select * from names where levenshtein(name, ?) < 3', 'Jan')
    

    在这个例子中,输出是

    Sam
    Ian
    John
    

    我没有在 Rails 中测试过,但我认为它应该可以工作,查询字符串只是传递到数据库。您可以使用 ActiveRecord::Base.connection.raw_connection 获取 Sqlite db 对象。 (我不知道如何配置 Rails 以便所有 ActiveRecord 连接都定义了函数——如果你在控制器中添加函数似乎确实可以工作,但这并不理想)。

    已经展示了这个可以是如何完成的,我不确定它是否应该在一个网络应用程序中完成。你可能不想在生产环境中使用 Sqlite。如果您使用例如它可能会很有用。 Postgres 在生产中具有自己的 levenshtein 函数(如 the Tin Man’s answer 中所建议的那样),但希望在开发中使用 Sqlite。

    【讨论】:

    • 其实是因为levenshtein函数耗时太长...也就是说你回答了我的问题。谢谢!如果您知道另一种测试两个字符串之间相似性的方法,请告诉我:D
    • 使用与生产环境不同的 DBM 开发是可以的,但不建议这样做,因为 SQL 实现中可能存在差异会泄漏回代码中;我们编写代码来容纳数据库,然后在针对不同的 DBM 推送到生产环境后会导致问题。考虑到 PostgreSQL 是免费的,并且几乎可以很好地适应开发人员将使用的任何机器,因此很难证明在开发过程中不使用它是合理的。是的,设置它有一点开销,但一旦完成,它就会非常透明。
    • @matt 你能评论一下为什么 SQLite 不适合生产环境吗?
    【解决方案2】:

    如果您需要检索列的值以将其插入到 Ruby 函数中,那么您必须首先检索该值。

    DBM 无法在您运行的代码中调用您的方法;您必须拥有该值,将其传递给您的方法,然后在辅助查询中使用结果。

    或使用内置 Levenshtein function 的 DBM,如 PostgreSQL 或在纯 SQL 中定义它。

    【讨论】:

    • 你能举个例子吗?
    • 我想你可以弄清楚那部分。进行选择以从正确的记录中获取所需的字段,计算距离,然后进行下一次搜索。
    • 这是否意味着我必须遍历名称列中的所有值?
    • 听起来您需要遵循最后一段中的建议。在大型数据库中(您不应该将其存储在 SQLite 中),检索列的每个值,然后在 Ruby 中处理它们,将是糟糕的系统设计。一个好的 DBM 具有完整的 SQL 实现,这将使编写一个函数或存储过程成为可能,这些函数或存储过程在 DBM 中执行以处理您的 Levenshtein 代码,并为您返回结果。
    • 在像 SQLite 这样的嵌入式数据库中,回调用户代码是微不足道的。
    猜你喜欢
    • 2014-05-27
    • 2018-01-18
    • 1970-01-01
    • 2023-03-24
    • 2021-02-13
    • 2018-05-26
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多