Elasticsearch 教程--搜索
搜索 – 基本工具
到目前为止,我们已经学习了Elasticsearch的分布式NOSQL文档存储,我们可以直接把JSON文档扔到Elasticsearch中,然后直接通过ID来进行调取。但是Elasticsearch真正的强大之处在于将混乱变得有意义——将大数据变成大量的信息。
这也是我们使用JSON文档而不是无规则数据的原因。Elasticsearch不仅仅只是存储文档,同时它还索引了这些文档以便搜索。文档中每一个字段都被索引并且可以被查询。不仅如此,在一个查询中,Elasticsearch可以使用所有索引,并且以惊人的速度返回结果。这是传统数据库永远也不能企及的。
这个搜索可以是:
- 类似于
年龄、性别、加入日期等结构化数据,类似于在SQL中进行查询。 - 全文搜索,查找整个文档中匹配关键字的内容,并根据相关性
- 或者结合两者。
虽然很多搜索操作是安装好Elasticsearch就可以用的,但是想发挥它的潜力,你需要明白以下内容:
| 名字 | 说明 |
|---|---|
| 映射 (Mapping) | 每个字段中的数据如何被解释 |
| 统计 (Analysis) | 可搜索的全文是如何被处理的 |
| 查询 (Query DSL) | Elasticsearch使用的灵活强的查询语言 |
上述的每一个内容都是一个大的主题,我们将会在之后的《深入搜索》中详细探讨它们。 本章中我们将针对先去介绍它们三个的基本概念 —— 已经足够能帮助你理解搜索是如何运作的了。
我们将向你介绍searchAPI的简单实用方式。
测试数据
我们本章使用的文档可以在下面的git中找到:https://gist.github.com/clintongormley/8579281
你可以下载然后导入到你的shell中以方便你的学习使用。
5.1 空白搜索
空白搜索
搜索API最常用的一种形式就是空白搜索,也就是不加任何查询条件的,只是返回集群中所有文档的搜索。
GET /_search
返回内容如下(有删减):
{
"hits" : {
"total" : 14,
"hits" : [
{
"_index": "us",
"_type": "tweet",
"_id": "7",
"_score": 1,
"_source": {
"date": "2014-09-17",
"name": "John Smith",
"tweet": "The Query DSL is really powerful and flexible",
"user_id": 2
}
},
... 9 个结果被隐藏 ...
],
"max_score" : 1
},
"took" : 4,
"_shards" : {
"failed" : 0,
"successful" : 10,
"total" : 10
},
"timed_out" : false
}
hits
返回内容中最重要的内容就是hits,它指明了匹配查询的文档的总数,hits数组里则会包含前十个匹配文档——也就是搜索结果。
hits数组中的每一条结果都包含了文档的_index, _type以及_id信息,以及_source字段。这也就意味着你可以直接从搜索结果中获取到整个文档的内容。这与其他搜索引擎只返回给你文档编号,还需要自己去获取文档是截然不同的。
每一个元素还拥有一个_score字段。这个是相关性评分,这个数值表示当前文档与查询的匹配程度。通常来说,搜索结果会先返回最匹配的文档,也就是说它们会按照_score由高至低进行排列。在这个例子中,我们并没有声明任何查询,因此_score就都会返回1
max_score数值会显示所有匹配文档中的_score的最大值。
took
took数值告诉我们执行这次搜索请求所耗费的时间有多少毫秒。
shards
_shards告诉了我们参与查询分片的总数,以及有多少successful和failed。通常情况下我们是不会得到失败的反馈,但是有的时候它会发生。如果我们的服务器突然出现了重大事故,然后我们丢失了同一个分片中主从两个版本的数据。在查询请求中,无法提供可用的备份。这种情况下,Elasticsearch就会返回`failed提示,但是它还会继续返回剩下的内容。
timeout
timed_out数值告诉了我们查询是否超时。通常,搜索请求不会超时。如果相比完整的结果你更需要的是快速的响应时间,这是你可以指定timeout值,例如10、"10ms"(10毫秒)或者"1s"(1秒钟):
GET /_search?timeout=10ms
Elasticsearch会尽可能地返回你指定时间内它所查到的内容。
Timeout并不是终止者
这里应该强调一下timeout并不会终止查询,它只是会在你指定的时间内返回当时已经查询到的数据,然后关闭连接。在后台,其他的查询可能会依旧继续,尽管查询结果已经被返回了。
使用超时是因为你要保障你的品质,并不是因为你需要终止你的查询。
5.2 多索引多类型
多索引,多类型
你是否注意到了《空白搜索》一章节的文档中包含了很多不同的类型 —— user与tweet,它们也分别来自us、gb这两个不同的索引?
当我们没有特别指定一个索引或者类型的时候,我们将会搜索整个集群中的所有文档。Elasticsearch会把搜索请求转发给集群中的每一个主从分片,然后按照结果的相关性得到前十名,并将它们返回给我们。
然而,往往我们只需要在某一个特定的索引的几个类型中进行搜索。我们可以通过在URL中定义它来实现这个功能:
| URL | 说明 |
|---|---|
/_search |
搜索所有的索引和类型 |
/gb/_search |
搜索索引gb中的所有类型 |
/gb,us/_search |
搜索索引gb以及us中的所有类型 |
/g*,u*/_search |
搜索所有以g或u开头的索引中的所有类型 |
/gb/user/_search |
搜索索引gb中类型user内的所有文档 |
/gb,us/user,tweet/_search |
搜索索引gb和 索引us中类型user以及类型tweet内的所有文档 |
/_all/user,tweet/_search |
搜索所有索引中类型为user以及tweet内的所有文档 |
当你在一个索引中搜索的时候,Elasticsearch或将你的搜索请求转发给相应索引中的所有主从分片,然后收集每一个分片的结果。在多个索引中搜索也是相同的流程,只不过是增加了一些参与分片。
重要提示
搜索一个拥有五个主分片的索引与搜索五个都只拥有一个主分片是完全一样的。
在后面,你将会了解到如何利用这一点,来根据你的需要灵活打造系统。
5.3 分页
分页
在《空白搜索》一节中,搜索结果告诉我们在集群中共有14个文档匹配我们的(空白)查询。但是在hits数组中只有10个文档。我们怎样才能看到其他的呢?
与SQL使用LIMIT来控制单“页”数量类似,Elasticsearch使用的是from以及size两个参数:
| 参数 | 说明 |
|---|---|
size |
每次返回多少个结果,默认值为10 |
from |
忽略最初的几条结果,默认值为0 |
假设每页显示5条结果,那么1至3页的请求就是:
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
当心不要一次请求过多或者页码过大的结果。它们会在返回前排序。一个请求会经过多个分片。每个分片都会生成自己的排序结果。然后再进行集中整理,以确保最终结果的正确性。
分布式系统中的大页码页面
为了说明白为什么页码过大的请求会产生问题,我们就先预想一下我们在搜索一个拥有5个主分片的索引。当我们请求第一页搜索的时候,每个分片产生自己前十名,然后将它们返回给请求节点,然后这个节点会将50条结果重新排序以产生最终的前十名。
现在想想一下我们想获得第1,000页,也就是第10,001到第10,010条结果,与之前同理,每一个分片都会先产生自己的前10,010名,然后请求节点统一处理这50,050条结果,然后再丢弃掉其中的50,040条!
现在你应该明白了,在分布式系统中,大页码请求所消耗的系统资源是呈指数式增长的。这也是为什么网络搜索引擎不会提供超过1,000条搜索结果的原因。
TIP
在《重索引》一章中,我们将详细探讨如何才能高效地获取大量数据。
5.4 查询语句
精简 搜索
搜索的API分为两种:其一是通过参数来传递查询的“精简版”查询语句(query string),还有一种是通过JSON来传达丰富的查询的完整版请求体(request body),这种搜索语言被称为查询DSL。
查询语句在行命令中运行点对点查询的时候非常实用。比如我想要查询所有tweet类型中,所有tweet字段为"elasticsearch"的文档:
GET /_all/tweet/_search?q=tweet:elasticsearch
下一个查询是想要寻找name字段为"john"且tweet字段为"mary"的文档,实际的查询就是:
+name:john +tweet:mary
但是经过百分号编码(percent encoding)处理后,会让它看起来稍显神秘:
GET /_search?q=%2Bname%3Ajohn+%2Btweet%3Amary
前缀"+"表示必须要满足我们的查询匹配条件,而前缀"-"则表示绝对不能匹配条件。没有+或者-的表示可选条件。匹配的越多,文档的相关性就越大。
字段_all
下面这条简单的搜索将会返回所有包含"mary"字符的文档:
GET /_search?q=mary
在之前的例子中,我们搜索tweet或者name中的文字。然而,搜索的结果显示"mary"在三个不同的字段中:
- 用户的名字为"Mary"
- 6个"Mary"发送的推文
- 1个"@mary"
那么Elasticsearch是如何找到三个不同字段中的内容呢?
当我们在索引一个文档的时候,Elasticsearch会将所有字段的数值都汇总到一个大的字符串中,并将它索引成一个特殊的字段_all:
{
"tweet": "However did I manage before Elasticsearch?",
"date": "2014-09-14",
"name": "Mary Jones",
"user_id": 1
}
就好像我们已经添加了一个叫做_all的字段:
"However did I manage before Elasticsearch? 2014-09-14 Mary Jones 1"
除非指定了字段名,不然查询语句就会搜索字段_all。
TIP: 在你刚开始创建程序的时候你可能会经常使用_all这个字段。但是慢慢的,你可能就会在请求中指定字段。当字段_all已经没有使用价值的时候,那就可以将它关掉。之后的《字段all》一节中将会有介绍
更加复杂的查询
再实现一个查询:
- 字段
name包含"mary"或"john" date大于2014-09-10_all字段中包含"aggregations"或"geo"
- 字段
+name:(mary john) +date:>2014-09-10 +(aggregations geo)
最终处理完的语句可读性可能很差:
?q=%2Bname%3A(mary+john)+%2Bdate%3A%3E2014-09-10+%2B(aggregations+geo)
正如你所看到的,这个简明查询语句是出奇的强大。在查询语句语法中,有关于它详细的介绍。借助它我们就可以在开发的时候提高很多效率。
不过,你也会发现简洁带来的易读性差和难以调试,以及它的脆弱:当其中出现-, :, / 或者 "时,它就会返回错误提示。
最后要提一句,任何用户都可以通过查询语句来访问臃肿的查询,或许会得到一些私人的信息,或许会通过大量的运算将你的集群压垮!
TIP
出于以上原因,我们不建议你将查询语句直接暴露给用户,除非是你信任的可以访问数据与集群的权限用户。
与此同时,在生产环境中,我们经常会使用到查询语句。在了解更多关于搜索的知识前,我们先来看一下它是怎样运作的。
Elasticsearch 教程--搜索的更多相关文章
- (转)ElasticSearch教程——汇总篇
https://blog.csdn.net/gwd1154978352/article/details/82781731 环境搭建篇 ElasticSearch教程——安装 ElasticSearch ...
- Centos安装elasticsearch教程
elasticsearch安装是ytkah在做laravel电商站内搜索要实现的,通过自己的搜索和学习能力不算很费力解决了.下面就整理一下安装elasticsearch教程,服务器是Centos 7, ...
- Elasticsearch实现搜索推荐词
本篇介绍的是基于Elasticsearch实现搜索推荐词,其中需要用到Elasticsearch的pinyin插件以及ik分词插件,代码的实现这里提供了java跟C#的版本方便大家参考. 1.实现的结 ...
- Elasticsearch教程
Elasticsearch教程 摘要: 参考资料Elasticsearch中文参考文档思维导图阅读全文 posted @ 2015-08-05 11:49 xingoo 阅读(18) | 评论 (0) ...
- ElasticSearch位置搜索
ElasticSearch位置搜索 学习了:https://blog.csdn.net/bingduanlbd/article/details/52253542 学习了:https://blog.cs ...
- ElasticSearch入门-搜索(java api)
ElasticSearch入门-搜索(java api) package com.qlyd.searchhelper; import java.util.Map; import net.sf.json ...
- PHP使用ElasticSearch做搜索
PHP 使用 ElasticSearch 做搜索 https://blog.csdn.net/zhanghao143lina/article/details/80280321 https://www. ...
- 十九种Elasticsearch字符串搜索方式终极介绍
前言 刚开始接触Elasticsearch的时候被Elasticsearch的搜索功能搞得晕头转向,每次想在Kibana里面查询某个字段的时候,查出来的结果经常不是自己想要的,然而又不知道问题出在了哪 ...
- Elasticsearch 为了搜索
前言 Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene 基础之上. Lucene 可以说是当下最先进.高性能.全功能的搜索引擎库--无论是开源还是 ...
随机推荐
- ABP理论学习之多租户
返回总目录 本篇目录 什么是多租户 ABP中的多租户 什么是多租户 维基百科:"软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务".一个 ...
- iOS开发系列--C语言之存储方式和作用域
概述 基本上每种语言都要讨论这个话题,C语言也不例外,因为只有你完全了解每个变量或函数存储方式.作用范围和销毁时间才可能正确的使用这门语言.今天将着重介绍C语言中变量作用范围.存储方式.生命周期.作用 ...
- 利用gulp解决前后端分离的header/footer引入问题
在我们进行前后端完全分离的时候,有一个问题一直是挺头疼的,那就是公共header和footer的引入.在传统利用后端渲染的情况下,我们可以把header.footer写成两个单独的模板,然后用后端语言 ...
- OAuth2 Backend Web Application 验证过程
本文是从我的 github 博客转载的,原文请看. 一图胜千言.图片请自由转载,请保留图片的原始签名.
- Module Zero安装
返回<Module Zero学习目录> 使用模板创建(自动方式) 手动安装 核心(领域)层 基础设施层 展示层 这里需要抱歉的是,这里使用的博客园的Markdown语法,代码显示不是很好看 ...
- 队列送券的实际应用--ConcurrentLinkedQueue并发队列
1.TicketQueue.java--队列封装类,负责如下职责:a.把活动登记对象放入队列中b.从队列中获取活动登记对象,并派券 package com.datong.pear.ticket; im ...
- c#设计模式-适配器模式
一. 适配器(Adapter)模式 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本接口不匹配而无法在一起工作的两个类能够在一起工作. 名称由来 这很像变压器(Adapter),变压 ...
- <dependency>
<dependency> <groupId>org.hibernate</groupId> ...
- KnockoutJS 3.X API 第六章 组件(3) 组件绑定
组件绑定将指定的组件注入到元素中,并且可选地将参数传递给它. 本节目录 一个例子 API 组件生命周期 备注1:仅限模板组件 备注2:使用没有容器元素的组件 备注3:将标记传递给组件 处置和内存管理 ...
- sql语句的优化分析
开门见山,问题所在 sql语句性能达不到你的要求,执行效率让你忍无可忍,一般会时下面几种情况. 网速不给力,不稳定. 服务器内存不够,或者SQL 被分配的内存不够. sql语句设计不合理 没有相应的索 ...