我会假设“not_analyzed”的字段没有被索引
这是一个容易做出的假设,但也是一个错误的假设。在 ES 中,'not_analyzed' 表示该字段中的数据未拆分为标记(分析)。数据仍然非常索引。
在 ES 中搜索的最快方法是使用过滤器。从第一个查询 DSL 页面:
过滤器非常方便,因为它们执行比普通查询好一个数量级,因为不执行评分并且它们被自动缓存。
由于过滤器要快得多,所以最快的查询几乎总是过滤后的查询:
{
"query": {
"filtered": {
"query": { 'match_all' : { } },
"filter": {
{ "term": { "owner": 123 }}
}
}
}
}
如过滤查询页面所述,过滤查询的默认查询是match_all
,因此该查询可以进一步缩短为:
{
"query": {
"filtered": {
"filter": {
{ "term": { "owner": 123 }}
}
}
}
}
过滤器的限制是它们是布尔值。文档要么完全匹配过滤器,要么不匹配。为了性能,建议尽可能使用过滤器进行约束,然后使用查询进行进一步匹配。
我已经构建了一个查询构建器,它解析 HTML 表单,然后提交搜索参数。构建器检查每个搜索参数中的通配符(? 或 *),如果存在,则使用通配符查询。如果没有,它会添加一个过滤器。我提供 UI 按钮,使用户可以通过单击数据轻松执行精确搜索。当他们使用这些时,搜索会命中过滤器并且速度很快。在等待几毫秒后,他们还可以键入string*
并获取他们想要的内容。
这是我的查询生成器的通用片段:
var filters = [], queries = [];
var searchVal = ..., searchField = ...;
var getWild = function (field, val, boost) {
var wc = { wildcard: { } };
wc.wildcard[field] = { value: val, boost: (boost || 1) };
return wc;
};
if (searchVal) {
if (/\*|\?/.test(searchVal)) {
queries.push(getWild(searchField, searchVal);
}
else {
filters.push({ term: {searchField: searchVal}});
}
}
我使用And
过滤器来约束所有精确匹配(日期范围、uid 约束等),然后将其余查询作为filtered -> bool
查询。它运行得非常好,我的 3 节点小型 ES 集群有 133,000,000 个文档,速度足够快。