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

jpe*_*pea 2 elasticsearch

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

"query": {
    "bool": {
      "must": [
        {
          "match": {
            "categories": "Electronic"
          }
        },
        {
          "match": {
            "categories": "Pop"
          }
        },
        {
          "match": {
            "instruments": "Female Vocal"
          }
        }
      ]
    }
}
Run Code Online (Sandbox Code Playgroud)

我在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
Run Code Online (Sandbox Code Playgroud)

因此,它与乐器领域的"声乐"部分相匹配,但不会与"女声"完全匹配.

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

编辑:为了解释其他字符,我稍微扩展了示例数据集:

[categories]=>R&B,Dance/House
[instruments] => Electronic Drums,Male Vocal,Synth
[moods] => Fun,Futuristic,Pulsing,Quirky,Rhythmic
Run Code Online (Sandbox Code Playgroud)

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

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

myesurl/tracks/_settings    
{
      "index": {
        "analysis": {
          "tokenizer": {
            "comma": {
              "type": "pattern",
              "pattern": ","
            }
          },
          "analyzer": {
            "tracks_analyzer": {
              "type": "custom",
              "tokenizer": "comma",
              "filter": [
                "trim",
                "lowercase"
              ]
            }
          }
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

然后我设置了一个映射:

{
  "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"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Val*_*Val 6

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

发生的事情是,在索引时,Female Vocal将分为两个标记female并将vocal其索引到instruments字段中.这同样适用于Male Vocal被索引视为两个标记malevocal.因此也会匹配字段Male Vocal.然后,当你在match荷兰国际集团上Female Vocal,什么情况是,搜索词进行分拆,小写字母以及进入femalevocal和术语vocal将匹配与这两个文件Male VocalFemale Vocal.

如果您想要完全匹配,则需要两件事:1.声明您需要与not_analyzed映射完全匹配的字符串字段2.使用不分析搜索项的term查询(或term过滤器).

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

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"
               },
               ...
           }
       }
   }
}'
Run Code Online (Sandbox Code Playgroud)

使用这样的映射,Female Vocal将不会被分析(即没有被索引为femalevocal),而是逐字索引为Female Vocal.

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

curl -XPOST localhost:9200/my_index/my_type/_search -d '{
    "query": {
        "bool": {
          "must": [
            {
              "term": {
                "categories": "Electronic"
              }
            },
            {
              "term": {
                "categories": "Pop"
              }
            },
            {
              "term": {
                "instruments": "Female Vocal"
              }
            }
          ]
        }
    }
}'
Run Code Online (Sandbox Code Playgroud)


jpe*_*pea 5

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

myesurl/tracks/_settings    
{
      "index": {
        "analysis": {
          "tokenizer": {
            "comma": {
              "type": "pattern",
              "pattern": ","
            }
          },
          "analyzer": {
            "tracks_analyzer": {
              "type": "custom",
              "tokenizer": "comma",
              "filter": [
                "trim",
                "lowercase"
              ]
            }
          }
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

然后我设置了一个映射:

{
  "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"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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


Lin*_*adu 5

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

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

"query":{
  "bool":{
     "should":[
        {
           "match":{
              "my_text":{
                 "query":"I want to buy a new new car",
                 "minimum_should_match":"90%"
              }
           }
        }
     ]
  }
}
Run Code Online (Sandbox Code Playgroud)