ES query_string match的区别之一
今天线上发现一个问题,从而引出对query_string 和 match 的区别的思考。
curl -XGET 'http://localhost:9200/*/*/_search?pretty' -d '{"from" : 0,"size" : 10,"fields" : ["title"],"query": {"query_string" : {"query" : "100CrMo7 +圆钢","fields" : ["title"]} }}' | grep "100CrMo7"
在这个例子中,在title中查找包含100CrMo7,并且包含圆钢的数据。
curl -XGET 'http://localhost:9200/*/*/_search?pretty' -d '{ "from" : 0, "size" : 10, "fields" : ["title"], "query": {"query_string" : {"query" : "100CrMo7 -圆钢","fields" : ["title"]} }}' | grep "100CrMo7"
在这个例子中,在title中查找包含100CrMo7,但是不 包含圆钢的数据。
注:替换为simple_query_string 结果好像不尽人意。有一两条数据 没有被过滤出。
而看下面的例子
curl -XGET 'http://localhost:9200/*/*/_search?pretty' -d '{ "size" : 10, "fields" : ["title"], "query" : { "bool" : { "must" : { "match" : { "_all" : { "query" : "100CrMo7 -圆钢", "type" : "boolean", "operator" : "AND", "boost" : 1.0 } } } } }}' | grep "100CrMo7"
无论是100CrMo7 -圆钢 还是 100CrMo7 +圆钢 结果没有发生变化。
看文档解释如下:
The match family of queries does not go through a "query parsing" process. It does not support field name prefixes, wildcard characters, or other "advanced" features.
已就是说后者没有经过查询分析的这个过程。
所以如果你使用后者时加入了如下代码:QueryParser.escape(keyword.trim()) 时,如果关键字里有"-" 这么一个特殊符号,比如 100CrMo7-3 , 那么你的查询结果可能就是空。 所以在使用QueryParser.escape(keyword.trim()) 要分情况。
我们看一下它的源代码:
public static String escape(String s) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); // These characters are part of the query syntax and must be escaped if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':' || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' || c == '|' || c == '&' || c == '/') { sb.append('\\'); } sb.append(c); } return sb.toString(); }
因为符号- 被转译了。
先看QueryStringQueryParser的解析过程。
再看MatchQueryParser类
后者没有转译特殊字符,就解释了使用QueryParser.escape(keyword.trim()) 查不到结果。
继续查看matchQuery.parse
它只是调用查询分析器(mapping里设置的)去解析各个字段。
点击parseContext.queryParser
看到有很多的解析包括 < >等符号。