ruby-on-rails - FTS - 优化的 pg_search 在搜索中不使用字典

标签 ruby-on-rails postgresql ruby-on-rails-4 full-text-search pg-search

我在 Rails 应用程序中的搜索功能有问题。我将 pg_search 与 Postgresql 一起使用,并将波兰语字典加载到其中。我做了 #343 RailsCasts 教程,当我使用默认 search() 方法时一切都很好(性能非常慢),但是当按照教程 SQL 查询中的建议进行优化时,它无法正常工作 - 不抛出任何错误,只是不使用字典。例如,通过短语“herbata owoc”它找到了所有非常正确的记录,虽然与默认的“搜索”方法不同,但是通过正确的短语“herbata owocowa”它找不到任何东西,当“搜索”方法返回时准确记录。

当然我做了添加索引的迁移。我还尝试了一些触发器等解决方案( http://railscasts.com/episodes/343-full-text-search-in-postgresql?view=comments ),但没有帮助。我正在使用 Ruby on Rails 4.0.5、PostgreSQL 9.1.13、pg_Search 0.7.6。

Controller 中的方法调用:

Product.text_search(params[:query])

模型“产品”:

include PgSearch

pg_search_scope :text_search, against: [:title, :description],
              using: {tsearch: {dictionary: "polish"}}

def self.text_search(query)
  if query.present?
    # search(query)
    rank = <<-RANK
      ts_rank(to_tsvector(products.title), plainto_tsquery(#{sanitize(query)})) + ts_rank(to_tsvector(products.description), plainto_tsquery(#{sanitize(query)}))
    RANK
    where("to_tsvector('polish', products.title) @@ :q or to_tsvector('polish', products.description) @@ :q", q: query.split(" ").join(" & ")).order("#{rank} DESC")
  else
    scoped
  end
end

迁移:

class AddSearchIndexToProducts < ActiveRecord::Migration
  def up
    execute "create index products_title on products using gin(to_tsvector('polish', title))"
    execute "create index products_description on products using gin(to_tsvector('polish', description))"
  end

  def down
    execute "drop index products_title"
    execute "drop index products_description"
  end
end

我的查询没有给出结果:

Product Load (1.2ms)
SELECT "products".* 
FROM "products" 
INNER JOIN "categories" ON "categories"."id" = "products"."category_id" 
WHERE 
    "products"."active" = 't' 
    AND "categories"."active" = 't' 
    AND (to_tsvector('polish', products.title) @@ 'herbata & owocowa' 
        OR to_tsvector('polish', products.description) @@ 'herbata & owocowa') 
        AND (1=1) 
ORDER BY 
    title, 
    ts_rank(to_tsvector(products.title), plainto_tsquery('herbata owocowa')) 
    + ts_rank(to_tsvector(products.description), plainto_tsquery('herbata owocowa'))
    DESC

search() 查询给出预期结果,但速度非常慢:

Product Load (15391.1ms)  
SELECT "products".*, ((ts_rank((to_tsvector('polish', coalesce("products"."title"::text, '')) || to_tsvector('polish', coalesce("products"."description"::text, ''))), (to_tsquery('polish', ''' ' || 'herbata' || ' ''') && to_tsquery('polish', ''' ' || 'owocowa' || ' ''')), 0))) AS pg_search_rank 
FROM "products" 
INNER JOIN "categories" ON "categories"."id" = "products"."category_id" 
WHERE 
    "products"."active" = 't' 
    AND "categories"."active" = 't' 
    AND (
        ((to_tsvector('polish', coalesce("products"."title"::text, '')) || to_tsvector('polish', coalesce("products"."description"::text, ''))) 
        @@ (to_tsquery('polish', ''' ' || 'herbata' || ' ''') 
            && to_tsquery('polish', ''' ' || 'owocowa' || ' ''')))
    ) 
    AND (1=1) 
ORDER BY 
    title, pg_search_rank DESC, "products"."id" ASC

我尝试编写类似于 search() 给出的 Select,但我失败了。

示例数据:

(1 例)

  • 默认的 search() 方法,短语:“herbata owocowa”,预期的前 5 个结果:

    [[0] #<Product:0x000000083fa3d8> {
                 :title => "BIOFIX Herbata Kompozycja Owocowa 60 szt",
           :description => "Propozycja od dobrze znanej i cenionej polskiej marki Biofix. Doskonała herbata owocowa, która zadowoli wszystkich miłośników bogatego smaku. Idealna propozycja na każdą porę dnia. Doskonale smakuje z miodem lub dodatkiem plastrów cytryny. Zapraszamy do zapoznania się z produktami z pozostałych kategorii. Zrób już dzisiaj zakupy przez internet, a nasze delikatesy chętnie dostarczą Ci smaczną paczkę."
    },
    [1] #<Product:0x000000083fa040> {
                 :title => "BIOFIX Herbata Premium Hawaii Dream 20 szt",
           :description => "Propozycja od dobrze znanej i cenionej polskiej marki Biofix. Doskonała herbata owocowa, która zadowoli wszystkich miłośników bogatego smaku. Idealna propozycja na każdą porę dnia. Doskonale smakuje z miodem lub dodatkiem plastrów cytryny. Zapraszamy do zapoznania się z produktami z pozostałych kategorii. Zrób już dzisiaj zakupy przez internet, a nasze delikatesy chętnie dostarczą Ci smaczną paczkę."
    },
    [2] #<Product:0x000000083f9c80> {
                 :title => "BOBOVITA Herbata dla dzieci cytrynowa 200 g",
           :description => "Herbatka owocowa Bobovita to łagodny napój dla niemowląt. Ma delikatny aromat i przyjemny smak, dzięki czemu jej picie jest prawdziwą przyjemnością. W chłodne dni przynosi uczucie ukojenia, a podana na zimno odświeża i orzeźwia. Nie zawiera substancji konserwujących i barwników. Produkt przeznaczony dla dzieci po 9 miesiącu życia. Nasz supermarket online to dobre rozwiązanie dla każdego."
    },
    [3] #<Product:0x000000083f9898> {
                 :title => "BOBOVITA Herbata dla dzieci malinowa z dziką różą 200 g",
           :description => "Herbatka owocowa Bobovita to łagodny napój dla niemowląt. Ma delikatny aromat i przyjemny smak, dzięki czemu jej picie jest prawdziwą przyjemnością. W chłodne dni przynosi uczucie ukojenia, a podana na zimno odświeża i orzeźwia. Nie zawiera substancji konserwujących i barwników. Produkt przeznaczony dla dzieci po 5 miesiącu życia. Nasz supermarket online to dobre rozwiązanie dla każdego."
    },
    [4] #<Product:0x000000083f9460> {
                 :title => "BOBOVITA Herbata dla dzieci malinowa z dziką różą 400 g",
           :description => "Herbatka owocowa Bobovita to łagodny napój dla niemowląt. Ma delikatny aromat i przyjemny smak, dzięki czemu jej picie jest prawdziwą przyjemnością. W chłodne dni przynosi uczucie ukojenia, a podana na zimno odświeża i orzeźwia. Nie zawiera substancji konserwujących i barwników. Produkt przeznaczony dla dzieci po 5 miesiącu życia. Zamów już teraz szybka dostawa do domu gwarantowana."
    }]
    
  • 自定义查询给出 nil,短语:“herbata owocowa”


(2 例)

  • 默认 search() 方法和自定义方法都给出相同的结果,短语:“herbata owoc”,前 5 个结果:

    [[0] #<Product:0x00000009f53120> {
                 :title => "ANIA Ciasteczka orkiszowe z goją 120 g",
           :description => "Wyjątkowo zdrowe, chrupiące orkiszowe ciasteczka z owocem Goji. Wypieczone z najlepszej jakości naturalnych składników. Stanowią idealny dodatek do filiżanki ciepłej kawy lub herbaty. Dostępne w szerokiej gamie smakowej. Zapraszamy do zapoznania się z produktami z pozostałych kategorii.  Złóż już dzisiaj zamówienie w naszych delikatesach online, gwarantujemy szybką dostawę.\r\n",
    },
    [1] #<Product:0x0000000a02df00> {
                 :title => "BIOFIX Herbata  Premium Aronia z Acai 20 szt",
           :description => "Propozycja od dobrze znanej i cenionej polskiej marki Biofix. Doskonała herbata z owoców aronii, która zadowoli wszystkich miłośników bogatego smaku. Idealna propozycja na każdą porę dnia. Doskonale smakuje z miodem lub dodatkiem plastrów cytryny. Zapraszamy do zapoznania się z produktami z pozostałych kategorii. Zrób już dzisiaj zakupy przez internet, a nasze delikatesy chętnie dostarczą Ci smaczną paczkę.",
    },
    [2] #<Product:0x0000000a02db90> {
                 :title => "BOBOVITA Herbata dla dzieci z owoców południowych 200 g",
           :description => "Herbatka owocowa Bobovita to łagodny napój dla niemowląt. Ma delikatny aromat i przyjemny smak, dzięki czemu jej picie jest prawdziwą przyjemnością. W chłodne dni przynosi uczucie ukojenia, a podana na zimno odświeża i orzeźwia. Nie zawiera substancji konserwujących i barwników. Produkt przeznaczony dla dzieci po 5 miesiącu życia. Nasz supermarket online to dobre rozwiązanie dla każdego.",
    },
    [3] #<Product:0x0000000a02d820> {
                 :title => "BONNE MAMAN Dżem z figi 370 g",
           :description => "Dżem przygotowywany według tradycyjnej francuskiej receptury, której korzenie sięgają XVI wieku. Doskonałe proporcje składników i duża zawartość owoców figi wpływają na unikalny smak i aromat tego dżemu. Znakomity do deserów, naleśników, omletów. Może stanowić zdrową alternatywę dla cukru i osłodzić niejedną herbatę. Supermarket internetowy czeka by dostarczyć Ci tę owocową słodycz zamkniętą w słoiczku.",
    },
    [4] #<Product:0x0000000a02d4b0> {
                 :title => "BONNE MAMAN Dżem z krojonej pigwy 370 g",
           :description => "Dżem przygotowywany według tradycyjnej francuskiej receptury, której korzenie sięgają XVI wieku. Doskonałe proporcje składników, w tym duża zawartość najstaranniej dobranych owoców pigwy wpływają na oryginalny i niepowtarzalny smak i konsystencję dżemu. Świetnie nadaje się do deserów, ciast oraz herbaty. Supermarket internetowy z radością dostarczy Ci słoiczek od Bonne Maman!",
    }]
    

最佳答案

好的 - 我已重新格式化 SQL 以尝试更清楚地了解正在发生的事情。

需要注意两点:

  1. 如果您选择字典('polish'),那么您应该到处 使用它,否则查询的某些部分可能会使用不同的(默认)字典。这可能就是您在第一种情况下得不到结果的原因。

  2. 如果您想使用索引,那么它需要与您查询的对象相匹配。在第二个查询中,您合并并连接了一堆字符串,因此不能使用索引。

但是,在您的第二个查询中,您似乎始终指定了相同的字典,这就是您得到结果的原因。

如果您确保您的第一个查询自始至终都指定了一个波兰语词典,它就有可能会使用索引。

您可能希望在单个“文档”上使用单个索引,并为标题和描述设置相关权重(参见 the manuals)

关于ruby-on-rails - FTS - 优化的 pg_search 在搜索中不使用字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25442555/

相关文章:

postgresql - 像这样从复合 PK 迁移到单一 PK 是否安全

python - Psycopg2 中的元命令 -\d 不工作

ruby-on-rails - 如何让 Ruby on Rails 输出 Bootstrap v3 脚手架?

ruby-on-rails - Join Tables 中的嵌套关​​系 - Rails

css - 在 Rails View 中使用内联 CSS 的 Assets 助手

ruby-on-rails - Rails 3 activerecord children of children 记录

ruby-on-rails - 无方法错误 : undefined method `bytesize' for #<Array:

ruby-on-rails - 从外部访问 WEBrick 服务器

postgresql - Postgres 损坏错误 : Duplicate rows with the same primary key

ruby-on-rails - Rails4 : How to display the data when association data doesn't exist