教程
关于 入门 为了搜索,你懂的 安装Elasticsearch 与Elasticsearch交互 面向文档 开始第一步 检索文档 分析 教程小结 分布式的特性 下一步 集群内部工作方式 空集群 集群健康 添加索引 增加故障转移 横向扩展 继续扩展 应对故障 数据吞吐 什么是文档? 索引一个文档 检索文档 检查文档是否存在 更新整个文档 创建一个新文档 删除文档 处理冲突 文档局部更新 检索多个文档 更省时的批量操作 结语 分布式文档存储 路由文档到分片 主分片和复制分片如何交互 新建、索引和删除文档 检索文档 局部更新文档 多文档模式 为什么是奇怪的格式? 搜索——基本的工具 空搜索 多索引和多类别 分页 简易搜索 映射和分析 映射及分析 确切值(Exact values) vs. 全文文本(Full text) 倒排索引 分析和分析器 映射 复合核心字段类型 结构化查询 请求体查询 结构化查询 Query DSL 查询与过滤 最重要的查询过滤语句 查询与过滤条件的合并 验证查询 结语 排序 相关性排序 多值字段字符串排序 相关性简介 数据字段 分布式搜索的执行方式 查询阶段 取回阶段 搜索选项 扫描和滚屏 索引管理 创建索引 索引设置 配置分析器 自定义分析器 类型和映射 根对象 元数据:_source 字段 元数据:_all 字段 文档 ID 动态映射 自定义动态索引 默认映射 重新索引数据 索引别名和零停机时间 入门 使文本可以被搜索 动态索引 近实时搜索 持久化变更 合并段 结构化搜索 查找准确值 组合过滤 查询多个准确值 包含,而不是相等 范围 处理 Null 值 关于缓存 过滤顺序 地理坐标点 地理坐标点 通过地理坐标点过滤 地理坐标盒模型过滤器 地理距离过滤器 缓存地理位置过滤器 减少内存占用 按距离排序 Geohashes Geohashes Geohashes 映射 geohash单元过滤器 地理位置聚合 地理位置聚合 按距离聚合 geohash单元聚合器 范围(边界)聚合器 地理形状 地理形状 映射地理形状 索引地理形状 查询地理形状 在查询中使用已索引的形状 地理形状的过滤与缓存 嵌套 嵌套-对象 嵌套-映射 嵌套-查询 嵌套排序 嵌套-集合

发布于 2016-02-29 14:41:53 | 241 次阅读 | 评论: 0 | 来源: 网络整理

查找准确值

对于准确值,你需要使用过滤器。过滤器的重要性在于它们非常的快。它们不计算相关性(避过所有计分阶段)而且很容易被缓存。我们今后再来讨论过滤器的性能优势【过滤器缓存】,现在,请先记住尽可能多的使用过滤器。

用于数字的 term 过滤器

我们下面将介绍 term 过滤器,首先因为你可能经常会用到它,这个过滤器旨在处理数字,布尔值,日期,和文本。

我们来看一下例子,一些产品最初用数字来索引,包含两个字段 priceproductID

POST /my_store/products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10, "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20, "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30, "productID" : "QQPX-R-3956-#aD8" }

我们的目标是找出特定价格的产品。假如你有关系型数据库背景,可能用 SQL 来表现这次查询比较熟悉,它看起来像这样:

SELECT document
FROM   products
WHERE  price = 20

在 Elasticsearch DSL 中,我们使用 term 过滤器来实现同样的事。term 过滤器会查找我们设定的准确值。term 过滤器本身很简单,它接受一个字段名和我们希望查找的值:

{
    "term" : {
        "price" : 20
    }
}

term 过滤器本身并不能起作用。像在【查询 DSL】中介绍的一样,搜索 API 需要得到一个查询语句,而不是一个 过滤器。为了使用 term 过滤器,我们需要将它包含在一个过滤查询语句中:

GET /my_store/products/_search
{
    "query" : {
        "filtered" : { <1>
            "query" : {
                "match_all" : {} <2>
            },
            "filter" : {
                "term" : { <3>
                    "price" : 20
                }
            }
        }
    }
}

`filtered` 查询同时接受接受 `query` 与 `filter`。 `match_all` 用来匹配所有文档,这是默认行为,所以在以后的例子中我们将省略掉 `query` 部分。 这是我们上面见过的 `term` 过滤器。注意它在 `filter` 分句中的位置。 执行之后,你将得到预期的搜索结果:只能文档 2 被返回了(因为只有 `2` 的价格是 `20`): ```json "hits" : [ { "_index" : "my_store", "_type" : "products", "_id" : "2", "_score" : 1.0, "_source" : { "price" : 20, "productID" : "KDKE-B-9947-#kL5" } } ] ``` 过滤器不会执行计分和计算相关性。分值由 `match_all` 查询产生,所有文档一视同仁,所有每个结果的分值都是 `1` #### 用于文本的 `term` 过滤器 像我们在开头提到的,`term` 过滤器可以像匹配数字一样轻松的匹配字符串。让我们通过特定 UPC 标识码来找出产品,而不是通过价格。如果用 SQL 来实现,我们可能会使用下面的查询: ```sql SELECT product FROM products WHERE productID = "XHDK-A-1293-#fJ3" ``` 转到查询 DSL,我们用 `term` 过滤器来构造一个类似的查询: ```json GET /my_store/products/_search { "query" : { "filtered" : { "filter" : { "term" : { "productID" : "XHDK-A-1293-#fJ3" } } } } } ``` 有点出乎意料:我们没有得到任何结果值!为什么呢?问题不在于 `term` 查询;而在于数据被索引的方式。如果我们使用 `analyze` API,我们可以看到 UPC 被分解成短小的表征: ```json GET /my_store/_analyze?field=productID XHDK-A-1293-#fJ3 ``` ```json { "tokens" : [ { "token" : "xhdk", "start_offset" : 0, "end_offset" : 4, "type" : "", "position" : 1 }, { "token" : "a", "start_offset" : 5, "end_offset" : 6, "type" : "", "position" : 2 }, { "token" : "1293", "start_offset" : 7, "end_offset" : 11, "type" : "", "position" : 3 }, { "token" : "fj3", "start_offset" : 13, "end_offset" : 16, "type" : "", "position" : 4 } ] } ``` 这里有一些要点: * 我们得到了四个分开的标记,而不是一个完整的标记来表示 UPC。 * 所有的字符都被转为了小写。 * 我们失去了连字符和 `#` 符号。 所以当我们用 `XHDK-A-1293-#fJ3` 来查找时,得不到任何结果,因为这个标记不在我们的倒排索引中。相反,那里有上面列出的四个标记。 显然,在处理唯一标识码,或其他枚举值时,这不是我们想要的结果。 为了避免这种情况发生,我们需要通过设置这个字段为 `not_analyzed` 来告诉 Elasticsearch 它包含一个准确值。我们曾在【自定义字段映射】中见过它。为了实现目标,我们要先删除旧索引(因为它包含了错误的映射),并创建一个正确映射的索引: ```json DELETE /my_store PUT /my_store { "mappings" : { "products" : { "properties" : { "productID" : { "type" : "string", "index" : "not_analyzed" } } } } } ``` 必须首先删除索引,因为我们不能修改已经存在的映射。 删除后,我们可以用自定义的映射来创建它。 这里我们明确表示不希望 `productID` 被分析。 现在我们可以继续重新索引文档: ```json POST /my_store/products/_bulk { "index": { "_id": 1 }} { "price" : 10, "productID" : "XHDK-A-1293-#fJ3" } { "index": { "_id": 2 }} { "price" : 20, "productID" : "KDKE-B-9947-#kL5" } { "index": { "_id": 3 }} { "price" : 30, "productID" : "JODL-X-1937-#pV7" } { "index": { "_id": 4 }} { "price" : 30, "productID" : "QQPX-R-3956-#aD8" } ``` 现在我们的 `term` 过滤器将按预期工作。让我们在新索引的数据上再试一次(注意,查询和过滤都没有修改,只是数据被重新映射了)。 ```json GET /my_store/products/_search { "query" : { "filtered" : { "filter" : { "term" : { "productID" : "XHDK-A-1293-#fJ3" } } } } } ``` `productID` 字段没有经过分析,`term` 过滤器也没有执行分析,所以这条查询找到了准确匹配的值,如期返回了文档 1。 #### 内部过滤操作 Elasticsearch 在内部会通过一些操作来执行一次过滤: 1. _查找匹配文档_。 `term` 过滤器在倒排索引中查找词 `XHDK-A-1293-#fJ3`,然后返回包含那个词的文档列表。在这个例子中,只有文档 1 有我们想要的词。 2. _创建字节集_ 然后过滤器将创建一个 _字节集_ —— 一个由 1 和 0 组成的数组 —— 描述哪些文档包含这个词。匹配的文档得到 `1` 字节,在我们的例子中,字节集将是 `[1,0,0,0]` 3. _缓存字节集_ 最后,字节集被储存在内存中,以使我们能用它来跳过步骤 1 和 2。这大大的提升了性能,让过滤变得非常的快。 当执行 `filtered` 查询时,`filter` 会比 `query` 早执行。结果字节集会被传给 `query` 来跳过已经被排除的文档。这种过滤器提升性能的方式,查询更少的文档意味着更快的速度。

最新网友评论  共有(0)条评论 发布评论 返回顶部

Copyright © 2007-2017 PHPERZ.COM All Rights Reserved   冀ICP备14009818号  版权声明  广告服务