【问题标题】:Join / split search words in elasticsearch (using tire)在 elasticsearch 中加入/拆分搜索词(使用轮胎)
【发布时间】:2013-02-09 18:41:21
【问题描述】:

我有以下分析器(对雪球的设置方式稍作调整):

  string_analyzer: {
    filter: [ "standard", "stop", "snowball" ],
    tokenizer: "lowercase"
  }

这是它应用到的字段:

  indexes :title, type: 'string', analyzer: 'string_analyzer'

  query do
    match ['title'], search_terms, fuzziness: 0.5, max_expansions: 10, operator: 'and'
  end

我的索引中有一条标题为 foo bar 的记录。

如果我搜索foo bar,它会出现在结果中。

但是,如果我搜索 foobar,它不会。

有人能解释一下原因吗?如果可能的话,我是怎么做到的?

有人能解释一下我怎样才能让这反过来也能正常工作,这样如果我有一个标题为 foobar 的记录,用户就可以搜索 foo bar 并看到结果吗?

谢谢

【问题讨论】:

    标签: ruby-on-rails-3 elasticsearch tire fuzzy-search


    【解决方案1】:

    您只能搜索索引中的标记。所以让我们看看你在索引什么。 您当前正在使用lowercase 标记器(将字符串标记为非字母字符并将它们小写)然后应用standard 过滤器(冗余,因为您没有使用standard 标记器),stopsnowball 过滤器。

    如果我们创建该分析器:

    curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1'  -d '
    {
       "settings" : {
          "analysis" : {
             "analyzer" : {
                "string_analyzer" : {
                   "filter" : [
                      "standard",
                      "stop",
                      "snowball"
                   ],
                   "tokenizer" : "lowercase"
                }
             }
          }
       }
    }
    '
    

    并使用analyze API 对其进行测试:

    curl -XGET 'http://127.0.0.1:9200/test/_analyze?pretty=1&text=foo+bar&analyzer=string_analyzer' 
    

    您会看到"foo bar" 生成术语["foo","bar"],而"foobar" 生成术语["foobar"]。因此索引"foo bar" 和搜索"foobar" 目前无法工作。

    如果您希望能够搜索“内部”单词,那么您需要将单词分解为更小的标记。为此,我们使用ngram 分析器。

    所以删除测试索引:

    curl -XDELETE 'http://127.0.0.1:9200/test/?pretty=1' 
    

    并指定一个新的分析器:

    curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1'  -d '
    {
       "settings" : {
          "analysis" : {
             "filter" : {
                "ngrams" : {
                   "max_gram" : 5,
                   "min_gram" : 1,
                   "type" : "ngram"
                }
             },
             "analyzer" : {
                "ngrams" : {
                   "filter" : [
                      "standard",
                      "lowercase",
                      "ngrams"
                   ],
                   "tokenizer" : "standard"
                }
             }
          }
       }
    }
    '
    

    现在,如果我们测试分析器,我们会得到:

    "foo bar" => [f,o,o,fo,oo,foo,b,a,r,ba,ar,bar]
    "foobar"  => [f,o,o,b,a,r,fo,oo,ob,ba,ar,foo,oob,oba,bar,foob,ooba,obar,fooba,oobar]
    

    因此,如果我们索引"foo bar" 并使用match 查询搜索"foobar",则该查询将成为查找任何这些标记的查询,其中一些标记存在于索引中。

    不幸的是,它还会与"wear the fox hat" (f,o,a) 重叠。虽然foobar 将出现在结果列表的较高位置,因为它有更多的共同标记,但您仍然会得到明显不相关的结果。

    这可以通过使用minimum_should_match参数来控制,例如:

    curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1'  -d '
    {
       "query" : {
          "match" : {
             "my_field" : {
                "minimum_should_match" : "60%",
                "query" : "foobar"
             }
          }
       }
    }
    '
    

    minimim_should_match 的确切值取决于您的数据 - 试验一下。

    【讨论】:

    • 感谢 DrTech。添加雪球作为过滤器有什么好处吗?还是没有任何意义,因为无论如何使用 ngrams 过滤器,单词的开头都会与搜索词匹配?
    • 去除停止过滤器是否有特殊原因,或者只是停止过滤器可以删除的某些单词可能是 ngrams 过滤器的块?
    • 正确,使用雪球过滤器没有任何好处,出于您陈述的原因,是的,停用词可能会干扰 ngram。我不会害怕停用词。看看我在stackoverflow.com/a/14661309/819598上的回答
    • 感谢 DrTech。我有一个小问题。我现在可以使用foo bar 进行搜索,它会返回包含foo barfoobar 的内容,但我似乎无法进行反向搜索——使用foobar 进行搜索并返回两个结果。我可以看到这可能是由于foo bar 的记录从来没有与foobar 匹配的索引项。有办法吗?我想我可能会尝试涵盖许多搜索可能性。
    • 您是否将my_field 映射为使用ngrams 分析器?您是否完全按照上述方式查询?如果是这样,则需要将 minimum_should_match 设置为 30% 或更低,以便 foobar 的查询也匹配 foobar
    猜你喜欢
    • 2012-03-22
    • 1970-01-01
    • 2012-10-19
    • 2015-04-21
    • 2012-08-24
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 2013-02-14
    相关资源
    最近更新 更多