【问题标题】:Elasticsearch with Tire: edgeNgram with multiple words带有轮胎的 Elasticsearch:带有多个单词的 edgeNgram
【发布时间】:2012-12-16 16:57:36
【问题描述】:

假设我有 5 个电影片名:

  • 无太阳
  • 珊莎
  • 原来如此
  • 索尔古德
  • 唯一的幸存者

我想实现一个具有这种预期行为的自动完成搜索字段:

  • "Sans" > Sans Soleil, Sansa
  • “Sans so” > Sans Soleil
  • “所以” > 就是这样,索尔·古德,唯一的幸存者
  • “原来如此” > 原来如此
  • “Sol”> Sol Goode,Sole Survivor,Sans Soleil

这个用例似乎很明显,肯定是很多人都在使用的,但我就是无法让它正常工作,而且我似乎找不到任何答案或文档来提供帮助。这是我目前的模型:

class Film < Media
  include Tire::Model::Search
  include Tire::Model::Callbacks

  settings  :analysis => {
              :filter => {
                :title_ngram  => {
                  "type"      => "edgeNGram",
                  "min_gram"  => 2,
                  "max_gram"  => 8,
                  "side"      => "front" }
              },
              :analyzer => {
                :title_analyzer => {
                  "tokenizer"    => "lowercase",
                  "filter"       => ["title_ngram"],
                  "type"         => "custom" }
              }
            } do
    mapping do
      indexes :title, :type => 'string', :analyzer => 'title_analyzer'
      indexes :int_english_title, :type => 'string', :analyzer => 'title_analyzer'
    end
  end
end

以及在我的 search_controller 中如何处理查询:

search = Tire.search ['books', 'films', 'shows'], :load => true, :page => 1, :per_page => 10 do |s|
    s.query do |query|
        query.string "title:#{params[:search]}"
    end
end
@results = search.results

这会产生一些奇怪的行为:

  • “Sans so”按此顺序返回“Sansa,Sans Soleil,So Is This”。
  • “So is”按此顺序返回“Sol Goode, Sans Soleil, Sole Survivor, So Is This”。

【问题讨论】:

  • 最新railscast(pro)中同一问题的不同处理方式
  • 有趣,你看过这集吗?如果它解决了我的确切用例,因为它能够正确地对具有多个单词的标题上的 ngram 命中进行排序,我可能会考虑订阅。
  • 我看过了。它不能解决您确切的问题,而是使用不同的方法。如果您开发 Rails 应用程序是为了赚钱,railscast 可以节省大量时间,就我而言,每个月的第一天我都会节省 9 美元。

标签: ruby-on-rails elasticsearch tire


【解决方案1】:

尝试关注

search = Tire.search ['books', 'films', 'shows'], :load => true, :page => 1, :per_page => 10 do |s|
      s.query do |q|
        q.boolean do |b|
          b.must {|m| m.string params[:search]} 
        end
      end
end

【讨论】:

  • 未在字符串中指定“title:”会搜索绕过我的 edgeNgram 分析器的 _all 字段,因此搜索“Sol”只会返回“Sol Goode”。我尝试将“title:#params[:search]”添加到您的块中,但遗憾的是它一直返回次优命中。
  • 你试过b.must{|m| m.string "title:#{params[:search]}"}
  • 是的,当我尝试得到与以前相同的结果时。
  • @Salil 无需将查询包装在布尔查询中——没有区别。此外,正如@gibson 所说,不指定title: 查询限定符将产生完全错误的结果。
【解决方案2】:

我认为您可以通过将match 查询设置为type:"phrase_prefix" 来实现您想要的。您的大多数示例(但不是全部)都可以使用。

使用 Ngram,您可以更好地控制流程,但它们的召回率相当高(它们通常返回比您想要的更多的数据),您必须与之抗争。这是您使用多个查询词(“Sans so”)观察到的“奇怪行为”,因为它们作为Sans OR so 查询有效地执行。

尝试使用default_operator: "AND" 选项(参见Tire 的query_string_test.rb),或者更确切地说是match 查询(参见Tire 的match_query_test.rb)和operator: "AND" 选项。

有一些关于自动完成、轮胎和 Ngram 的文章可用:

【讨论】:

  • 正如您正确指出的那样,处理空白是主要问题。我曾尝试使用default_operator: "AND",但没有取得多大成功,但与type:"phrase_prefix" 匹配似乎可以解决问题!你知道为什么带有AND 的query_string 不起作用吗?我还调整了每个索引的映射以使用单独的:index_analyzer:search_analyzer。除了你链接的文章,我还可以推荐阅读这篇文章,它彻底打破了搜索过程,让事情变得更清晰:euphonious-intuition.com/2012/08/…
  • 使用“AND”运算符,我认为“sans so”查询不应该返回“So Is This”——因为“sans”部分不会分解为“So Is”中的任何 ngram这个”,除非我弄错了。
  • phrase_prefix 类型的 match 实际上应该非常适合简单的自动完成。当然,如前所述,使用 Ngram,您可以获得更大的灵活性和更高的召回率。
  • 拆分 index_search_ 分析器是个好主意,因为您的查询不会被标记为 ngram——这是您想要的,一个人在您的网站上执行的查询已经是“伪语法”了,因为她只写了“部分单词”。
猜你喜欢
  • 1970-01-01
  • 2013-03-03
  • 2014-07-11
  • 1970-01-01
  • 2017-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
相关资源
最近更新 更多