Elasticsearch将精确的术语与不同领域的空格匹配

时间:2015-08-21 20:55:47

标签: elasticsearch

我的弹性数据设置了不同的字段:类别,子类别,乐器和情绪。我的目标是为所有传递给它的关键字提供完全匹配的结果,并且仅返回与所有关键字匹配的结果。到目前为止,这似乎有效,直到我使用由空格分隔的多个单词组成的关键字,如下所示:

"query": {
    "bool": {
      "must": [
        {
          "match": {
            "categories": "Electronic"
          }
        },
        {
          "match": {
            "categories": "Pop"
          }
        },
        {
          "match": {
            "instruments": "Female Vocal"
          }
        }
      ]
    }
}

ES中的数据包含此类数据:

[name] => Some Data Name
[categories] => Electronic,Pop
[subcategories] => 1970s,Alternative,Experimental,Retro
[instruments] => Electronic Drums,Male Vocal,Synth
[moods] => Fun,Futuristic,Pulsing,Quirky,Rhythmic

所以,它匹配" Vocal"乐器领域的一部分,但没有为女性声乐"完成匹配。

这可能是由ES过滤器解决的吗?

修改: 为了解释其他字符,我稍微扩展了样本数据集:

[categories]=>R&B,Dance/House
[instruments] => Electronic Drums,Male Vocal,Synth
[moods] => Fun,Futuristic,Pulsing,Quirky,Rhythmic

因此,可能会使用&符号,斜杠和空格。逗号会将单独的术语分开。

解决 我最终更多地关注分析器,并意识到我可能需要创建一个自定义的分析器来解释我的关键字的边界。

myesurl/tracks/_settings    
{
      "index": {
        "analysis": {
          "tokenizer": {
            "comma": {
              "type": "pattern",
              "pattern": ","
            }
          },
          "analyzer": {
            "tracks_analyzer": {
              "type": "custom",
              "tokenizer": "comma",
              "filter": [
                "trim",
                "lowercase"
              ]
            }
          }
        }
      }
    }

然后我设置了映射:

{
  "track": {
    "properties": {
      "categories": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      },
      "subcategories": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      },
      "instruments": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      },
      "moods": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      }
    }
  }
}

然后将内容推送到elasticsearch中。似乎按预期工作。它现在考虑关键字中的任何字符,只要该关键字与由分隔逗号创建的标记匹配即可。

3 个答案:

答案 0 :(得分:5)

使用match查询意味着您输入的任何字符串都由标准分析器进行分析,因此会分隔在空格和小写字母上。正如你所看到的那样,只要你为每个字段匹配一个单词,你就会很好,但是,只要你搜索的内容包含空格,就会产生乐趣。

在索引编制时,Female Vocal会被分成两个标记femalevocal,并被编入instruments字段。将Male Vocal索引为两个令牌malevocal也是如此。因此也会将字段与Male Vocal匹配。然后当您match Female Vocal时,搜索字词会被分割并缩小为femalevocal以及字词{{ 1}}会将这两个文档与vocalMale Vocal匹配。

如果您想要完全匹配,则需要两件事: 1.声明您需要在映射中与Female Vocal完全匹配的字符串字段 2.使用不分析搜索字词的term queries(或term filters)。

第一点很容易用这样的映射:

not_analyzed

通过此类映射,curl -XPUT localhost:9200/my_index -d '{ "mappings": { "my_type": { "properties": { "categories": { "type": "string", "index": "not_analyzed" }, "subcategories": { "type": "string", "index": "not_analyzed" }, "instruments": { "type": "string", "index": "not_analyzed" }, "moods": { "type": "string", "index": "not_analyzed" }, ... } } } }' 将不会被分析(即未编入Female Vocalfemale索引),而是逐字索引为vocal

然后,您可以使用如下查询查询确切的字段值:

Female Vocal

答案 1 :(得分:3)

我最终更多地关注分析器,并意识到我可能需要创建一个自定义分析器以解释我的关键字的边界。

myesurl/tracks/_settings    
{
      "index": {
        "analysis": {
          "tokenizer": {
            "comma": {
              "type": "pattern",
              "pattern": ","
            }
          },
          "analyzer": {
            "tracks_analyzer": {
              "type": "custom",
              "tokenizer": "comma",
              "filter": [
                "trim",
                "lowercase"
              ]
            }
          }
        }
      }
    }

然后我设置了映射:

{
  "track": {
    "properties": {
      "categories": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      },
      "subcategories": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      },
      "instruments": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      },
      "moods": {
        "type": "string",
        "analyzer": "tracks_analyzer"
      }
    }
  }
}

然后将内容推送到elasticsearch中。似乎按预期工作。它现在可以解释关键字中的任何字符,只要该关键字与由分隔的逗号创建的标记匹配即可。

答案 2 :(得分:0)

一个不错的解决方案是使用matchminimum_should_match,提供要匹配的单词的百分比。它可以是100%,并将返回至少包含给定文本的结果;

这种方法不要考虑单词的顺序很重要。

"query":{
  "bool":{
     "should":[
        {
           "match":{
              "my_text":{
                 "query":"I want to buy a new new car",
                 "minimum_should_match":"90%"
              }
           }
        }
     ]
  }
}