用重音字符搜索

时间:2017-01-30 04:09:08

标签: mysql ruby-on-rails ruby

我有一个存储标题和歌词的应用程序。有些歌曲是西班牙语,包含áccénts。我正在尝试编写一种搜索方法,用户可以在其中输入不带重音的单词。例如,假设标题中包含“papá”一词。如果用户键入“papa”,它仍然应该在标题中找到该单词的歌曲。

这是我到目前为止所拥有的。它处理通配符并搜索3列。

class Song < ApplicationRecord
  def self.search(query)
    return all unless query.present?

    # for case insensitive search
    like = Rails.env.production? ? 'ILIKE' : 'LIKE'

    # for wildcards
    q = ["%#{query}%"] * 3

    # columns that I will search through song.number, song.title, song.lyrics
    search_phrase = "number #{like} ? OR title #{like} ? OR lyrics #{like} ?"

    where([search_phrase] + q)
  end
end

3 个答案:

答案 0 :(得分:2)

您可以使用整理:

search_phrase = "number #{like} ? OR title COLLATE Latin1_general_CI_AI #{like} ? OR lyrics #{like} ?"

CI代表不区分大小写,AI代表重音不敏感。

答案 1 :(得分:0)

使用postgresql实现此目的的最佳方法是添加unaccent扩展名:

class AddUnaccentExtension < ActiveRecord::Migration
  def change
    enable_extension "unaccent"
  end
end

然后当您想要查询结果时:

search_phrase = "unaccent(number) #{like} unaccent(?) OR unaccent(title) #{like} unaccent(?) OR unaccent(lyrics) #{like} unaccent(?)"

请记住这只适用于postgresql,我建议你用作开发数据库,​​以防止发生奇怪的事情

答案 2 :(得分:0)

如果您无法使用COLLATE Latin1_general_CI_AIpg设置,请尝试此操作。重复列,一个重音,一个不重音。积分转到thisthis回答。

class Song < ApplicationRecord
  before_save :i18n

  def self.search(query)
    return all unless query.present?

    like = Rails.env.production? ? 'ILIKE' : 'LIKE'

    q = ["%#{query}%"] * 3

    search_phrase = "number #{like} ? OR ai_title #{like} ? OR ai_lyrics #{like} ?"

    where([search_phrase] + q)
  end

  def i18n
    self.ai_title = I18n.transliterate title
    self.ai_lyrics = I18n.transliterate lyrics
  end
end

我的迁移看起来像:

class CreateSongs < ActiveRecord::Migration[5.0]
  def change
    create_table :songs do |t|
      ...
      t.string :title
      t.string :ai_title, index: true
      t.text :lyrics
      t.text :ai_lyrics, index: true
      ...
    end
  end
end

适用于许多数据库设置。我觉得这很有用。