一. Elasticsearch简介
ES是一个基于Lucene的搜索服务器,它提供一个分布式多用户能力的全文搜索引擎,基于RESTful web接口,ES是使用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能达到实时搜索、稳定、可靠、快速、安装使用方便。
Elasticsearch是一个分布式、可扩展、实时的搜索与数据分析引擎。
Elasticsearch被用作全文搜索、结构化搜索、分析以及这三个功能的组合。
Elasticsearch是一个开源的搜索引擎,建立在一个全文搜索引擎库Apache Lucene基础之上。
Elasticsearch使用Java编写内部使用Lucene做索引和搜索,其目的是使全文索引变得简单,通过隐藏Lucene的复杂性,取而代之的提供一套简单一致的RESTful API。
归纳总结
- 一个分布式的实时文档存储,每个字段可被索引和搜索。
- 一个分布式实时分析的搜索引擎
- 能胜任上百个服务节点的扩展,并支持PB级别的结构化或非结构化数据。
二. Elasticsearch安装
操作系统:Ubuntu 16.04 LTS
1. 安装java
# 查看java版本
$ java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
# java编译器
$ javac
Elasticsearch recommends Oracle JDK version 1.8.0_73, but the native Ubuntu OpenJDK native package for the JRE works as well.
推荐安装JDK8
$ sudo add-apt-repository -y ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt-get -y install oracle-java8-installer
$ java -version
2. 安装Elasticsearch
建议采用源码包安装,使用 sudo apt-get install elasticsearch
出现下列错误。
# 安装elasticsearch
$ sudo apt-get update
$ sudo apt-get install elasticsearch
# 安装curl
$ sudo apt-get install curl
$ curl -version
# 查看系统类型
$ ps -p 1
# systemd下启动、关闭、重启elasticsearch
$ sudo systemctl start elasticsearch.service
$ sudo systemctl stop elasticsearch.service
$ sudo systemctl restart elasticsearch.service
$ sudo systemctl status elasticsearch.service
# 查看elasticsearch日志
$ ll /var/log/elasticsearch/
#查看日志
$ sudo journalctl -f
$ sudo journalctl --unit=elasticsearch
## 测试elasticsearch
$ curl 'http://localhost:9200/?pretty'
出现问题
jc@jcos:~$ curl 'http://127.0.0.1:9200/?pretty'
curl: (7) Failed to connect to 127.0.0.1 port 9200: 拒绝连接
root@jcos:~# curl -XGET 'localhost:9200'
curl: (7) Failed to connect to 127.0.0.1 port 9200: 拒绝连接
# 查看9200端口
root@jcos:~# netstat -tulpn | grep 9200
解决方案参照:
https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-elasticsearch-on-ubuntu-14-04
3. 源码包安装
下载最新版本的 elasticsearch
目前最新版本
https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.3.deb
# wget 下载
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.3.deb
# 解压安装deb
$ sudo dpkg -i elasticsearch-5.4.3.deb
# 安装后elasticsearch位于
$ cd /usr/share/elasticsearch/
# 开启服务
$ system.md start elasticsearch.service
测试:启动elasticsearch节点
$ curl -X GET 'http://localhost"9200'
{
"name" : "orc_HnJ",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "m9RkECrAToWEVAjEdpidMw",
"version" : {
"number" : "5.4.3",
"build_hash" : "eed30a8",
"build_date" : "2017-06-22T00:34:03.743Z",
"build_snapshot" : false,
"lucene_version" : "6.5.1"
},
"tagline" : "You Know, for Search"
}
将ES加入到系统启动文件并启动ES服务
# 加入开启自启动
$ sudo update-rc.d elasticsearch default 95 1
# 启动服务
$ sudo /etc/init.d/elasticsearch start
# CURL测试
$ curl -X GET "http://localhost:9200"
单个节点可作为一个运行中Elasticsearch实例,而一个集群是一组拥有相同cluster.name的节点,他们能一起工作并共享数据,还提供容错和可伸缩性。可在/etc/elasticsearch.yml
配置文件中修改cluster.name
,该节点会在节点启动时加载。
3. 安装Kibana
kibana是一个用于Elasticsearch分析和查询的仪表盘,它最吸引人的应该是NB的图标和表现能力。
下载安装 kibana
https://www.elastic.co/downloads/kibana
Kibana服务
# 启动kibana
$ systemctl start kibana.service
# 关闭kibana
$ systemctl stop kibana.service
# 查看kibana状态
$ systemctl status kibana.service
# 重启 kibana
$ systemctl restart kibana.service
# 使用deb安装kibana位于
$ cd /usr/share/kibana/
地址栏输入 localhost:5601
4. 安装Sense
Sense是一个Kibana应用,它提供交互式控制台,通过浏览器直接向Elasticsearch提交请求。
https://github.com/elastic/sense
HEADS UP: This repo is deprecated. Sense is now included as Console in Kibana 5.0. File issues over at elastic/kibana
目前sense已经集成到Kibana5中,访问 http://localhost:5601
打开左侧菜单栏 Dev Tools
此处就是 sense
。
例如:计算集群中文档的数据量
在Dev Tools中输入
GET /_count
{
“query":{
"match_all":{}
}
}
三. 和Elasticsearch交互
和Elasticsearch交互取决于你是否使用java,ES为Java用户提供两种内置客户端:
节点客户端(node cilent)
节点客户端作为一个非数据节点加入到本地集群中,换句话说它本身不保存任何数据,但是它知道数据在集群中那个节点中,并可把请求转发到正确的节点。传输客户端(transport client)
轻量级的传输客户端可将请求发送到远程集群,它本身不加入集群,但可将请求转发到集群中的一个节点上。
两个java客户端都是通过9300端口并使用本地ES传输协议和集群交互,集群中的节点通过端口9300彼此通信。若端口没有打开,节点将无法形成一个集群。
基于HTTP协议,以JSON为数据交换格式的RESTful API
其他所有语言都可使用RESTful API,通过9200端口与ES通信,可使用你喜欢的web客户端,设置可通过curl命令与ES通信。
四. 面向文档
ES是面向文档的,意味着可存储整个对象或 文档,而且索引每个文档的内容使之可被检索。在ES中,对文档进行索引、检索、排序、过滤而不是对行列数据,这种不同的思考数据的方式,也是 ES 能支持复杂全文检索的原因。Elasticsearch 使用 Javascript Object Notation 或 JSON 作为文档的序列化格式。
案例:创建一个雇员目录的业务需求
- 支持包含多值标签、数值、全文本数据
- 检索任一雇员的完整信息
- 允许结构化搜索,比如查询30岁以上的员工
- 允许简单的全文搜索以及较复杂的短语搜索
- 支持在匹配文档内容中高亮显示搜索片段
- 支持基于数据创建和管理分析仪表盘
1. 索引雇员文档
以雇员文档形式存储,一个文档代表一个雇员。存储数据到 Elasticsearch 的行为叫做索引,但在索引一个文档之前,需确定文档存储位置。
一个 Elasticsearch 集群可包含多个索引,相应每个索引可包含多个类型,不同类型存储多个文档,每个文档有多个属性。
一个索引类似于关系数据库中一个数据库,一个存储关系文档的地方,索引一个文档就是存储一个文档到一个索引(名称)中以便被检索和查询。关系数据库通过增加一个索引到指定列以提升数据检索速度。elasticsearch使用一个叫做倒序索引的结构来达到相同目的。
默认一个文档中每个属性都是被索引的和可搜索的,一个没有倒序索引的属性是不能被搜索的。
对于雇员目录将做如下操作
- 每个雇员索引一个文档,包含雇员的所有信息。
- 每个文档都将是 employee 类型
- employee 类型位于 megacorp内
- 该索引保存在Elasticsearch集群中
在Dev Tool
输入
// 创建一个索引或执行每个属性的数据类型 : megacorp 索引名称 / employee 类型名称 / 1 特定雇员编号
// 请求体,JSON文档中包含员工详细信息
PUT /megacorp/employee/1
{
"firstname":"John",
"lastname":"smith",
"age":25,
"introduce":"i love to go rock climbing",
"interests": ["sports", "music"]
}
返回结果
{
"_index": "megacorp",
"_type": "employee",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
继续创建索引
PUT /megacorp/employee/2
{
"firstname":"Jane",
"lastname":"Smith",
"age":32,
"introduce":"i like to collect rock albums",
"interests":["music"]
}
PUT /megacorp/employee/3
{
"firstname":"Douglas",
"lastname":"Fir",
"age":35,
"introduce":"i like to build cabinets",
"interests":["forestry"]
}
2. 检索文档 GET
检索单个雇员的数据,执行一个HTTP GET请求并指定文档地址-索引库、类型和ID,即可返回原始的JSON文档。
GET megacorp/employee/1
返回
{
"_index": "megacorp",
"_type": "employee",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"firstname": "John",
"lastname": "Smith",
"age": 25,
"introduce": "i love to go rock climing",
"interests": [
"sports",
"music"
]
}
}
GET megacorp/employee/2
GET megacorp/employee/3
HTTP命令
- GET 检索文档
- PUT 新增文档
- DELETE 删除文档
- HEAD 检查文档是否存在
3. 轻量搜索
# 搜索所有雇员
GET megacorp/employee/_search
使用索引库megacorp以及类型employee,返回结果包括3个文档,放在数组hits中。一个搜索默认返回10条结果。
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "megacorp",
"_type": "employee",
"_id": "2",
"_score": 1,
"_source": {
"firstname": "Jane",
"lastname": "Smith",
"age": 32,
"introduce": "i like to collect rock albums",
"interests": [
"music"
]
}
},
{
"_index": "megacorp",
"_type": "employee",
"_id": "1",
"_score": 1,
"_source": {
"firstname": "John",
"lastname": "Smith",
"age": 25,
"introduce": "i love to go rock climing",
"interests": [
"sports",
"music"
]
}
},
{
"_index": "megacorp",
"_type": "employee",
"_id": "3",
"_score": 1,
"_source": {
"firstname": "Douglas",
"lastname": "Fir",
"age": 35,
"introduce": "i like to build cabinets",
"interests": [
"forestry"
]
}
}
]
}
}
需求:搜索姓名为 Smith 的雇员
使用高亮搜索,涉及到查询字符串(query-string_)搜索,通过一个URL参数来传递查询信息给搜索接口。
GET magacorp/employee/_search?q=lastname:Smith
3. 查询表达式搜索
Query-string
搜索通过命令非常方便地进行临时性的即席搜索,但它由自身的局限性。Elasticsearch
提供了丰富灵活的查询语言叫做查询表达式。
GET megacorp/employee/_search
{
"query":{
"match":{
"lastname":"Smith"
}
}
}
不再使用query-string参数,而使用JSON构造的请求体替代,并使用一个match查询。
4. 复杂的搜索
需求:搜索姓氏为Smitch且年龄大于30的雇员
GET megacorp/employee/_search
{
"query":{
"bool":{
"must":{
"match":{"lastname":"smith"}
}
},
"filter":{
"range":{
"age":{"gt":30}
}
}
}
}
使用range过滤器,找到年龄大于30的文档。
添加了一个过滤器用于执行一个范围查询,并复用之前的match查询。
5. 全文搜索(_search)
需求:搜索所有喜欢攀岩(rock climbing)的雇员
GET megacorp/employee/_search
{
"query":{
"match":{
"introduce":"rock climbing"
}
}
}
结果按相关性排序,即每个文档跟查询的匹配程度,第一个最高得分的结果很明显。
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.26742277,
"hits": [
{
"_index": "megacorp",
"_type": "employee",
"_id": "2",
"_score": 0.26742277,
"_source": {
"firstname": "Jane",
"lastname": "Smith",
"age": 32,
"introduce": "i like to collect rock albums",
"interests": [
"music"
]
}
},
{
"_index": "megacorp",
"_type": "employee",
"_id": "1",
"_score": 0.26742277,
"_source": {
"firstname": "John",
"lastname": "Smith",
"age": 25,
"introduce": "i love to go rock climing",
"interests": [
"sports",
"music"
]
}
}
]
}
}
6. 短语搜索(match_phrase)
需求:仅匹配同时包含rock和albums,且二者以短语 rock albums 形式紧挨着的雇员记录。
GET megacorp/employee/_search
{
"query":{
"match_phrase":{
"introduce":"rock albums"
}
}
}
7. 高亮搜索(highlight)
GET megacorp/employee/_search
{
"query":{
"match_phrase":{
"introduce":"rock albums"
}
},
"highlight": {
"fields": {
"introduce": {}
}
}
}
返回结果中以HTML的em标签封装
GET megacorp/employee/_search
{
"query":{
"match_phrase":{
"introduce":"rock albums"
}
},
"highlight": {
"fields": {
"introduce": {}
}
}
}
8. 分析
支持管理这对雇员目录做分析,Elasticsearch聚合(aggregations)允许我们基于数据生成一些精细的分析结果。集合与SQL中的GROUP BY类似,但更强大。
# 挖掘出雇员中最受欢迎的兴趣爱好
GET megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
# 查询名叫Smith的雇员中最受欢迎的兴趣爱好可直接添加适当的查询来组合
GET /megacorp/employee/_search
{
"query": {
"match": {
"lastname": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}
# 查询特定兴趣爱好员工的平均年龄,聚合支持分级汇总
GET /megacorp/employee/_search
{
"aggs" : {
"all_interests" : {
"terms" : { "field" : "interests" },
"aggs" : {
"avg_age" : {
"avg" : { "field" : "age" }
}
}
}
}
}
五. 集群内的原理
ElasticSearch 的主旨是随时可用和按需扩容,而扩容可通过购买性能更强大(垂直扩容或纵向扩容)或数量更多的服务器来实现。虽然ES可获益于更强大的硬件设备,但垂直扩容是有限的。真正的扩容能力是来自于水平库扩容 - 为集群添加更多的节点,并将负载压力和稳定分散到节点中。
对于大多数数据库而言,通常需要对应用进行非常大的改动,才能利用上横向扩容和新增资源。ES天生就是分布式的,它知道如何通过管理多节点来提高扩容性和可用性,这也意味着应用无需关注这个问题。