弹性搜索ElasticSearch安装及基础入门教程
本博文仅供记录笔记,博文记录得不是很全,详情请移步至《ElasticSearch官方文档》。小编初次接触Elastic,若有什么写得不对的地方欢迎各位大佬留言。
简介
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
一、安装
1. 下载Elastic
提前:Elastic需要 Java 8 环境。如果你的机器还没安装 Java,请先安装JDK,注意要保证环境变量JAVA_HOME正确设置。
安装完 Java,就可以跟着官方文档安装 Elastic。直接下载压缩包比较简单。
Elastic可跨平台使用,小编这里就以Windows为例。
下载地址:Elastic官网下载。
如图点击即可下载(这里下载的是压缩包):
小编下载的版本是7.7.1
,现在官网已经更新到7.8.0
了。
2. 解压Elastic
解压此压缩包到指定目录,打开./elasticsearch-7.7.1
,目录结构如下:
- bin:脚本文件,里面包括启动elasticSearch,安装插件等。
- config:配置文件目录,里面有个很重要的配置文件elasticsearch.yml
- data:数据文件
- jdk:java运行环境
- lib:java类库
- logs:日志文件
- modules:包含所有的es模块
- plugins:包含所有已经安装的插件
2. 启动Elastic
进入./elasticsearch-7.7.1/bin
,Windows下双击运行elasticsearch.bat
脚本文件即可启动Elastic。
Linux下命令启动:
./elasticsearch
如果这时报错"max virtual memory areas vm.maxmapcount [65530] is too low",要运行下面的命令:
sudo sysctl -w vm.max_map_count=262144
如果一切正常,Elastic 就会在默认的9200端口运行。可通过postman发送GET请求,会得到说明信息
RQ:
GET localhost:9200
RS:
{
"name": "DESKTOP-CYK",
"cluster_name": "elasticsearch",
"cluster_uuid": "8qzW6nfoTAa7-YtloNrXew",
"version": {
"number": "7.7.1",
"build_flavor": "default",
"build_type": "zip",
"build_hash": "ad56dce891c901a492bb1ee393f12dfff473a423",
"build_date": "2020-05-28T16:30:01.040088Z",
"build_snapshot": false,
"lucene_version": "8.5.1",
"minimum_wire_compatibility_version": "6.8.0",
"minimum_index_compatibility_version": "6.0.0-beta1"
},
"tagline": "You Know, for Search"
}
上面RS中,请求9200
端口,Elastic 返回一个 JSON 对象,包含当前节点、集群、版本等信息。
默认情况下,Elastic 只允许本机访问,如果需要远程访问,可以修改 Elastic 安装目录的config/elasticsearch.yml
文件,去掉network.host
的注释,将它的值改成0.0.0.0
,然后重新启动 Elastic。
network.host: 0.0.0.0
上面代码中,设成0.0.0.0
让任何人都可以访问。线上服务不要这样设置,要设成具体的 IP,并加上cluster.initial_master_nodes: ["node-name"]
。
二、基本概念
1. 节点(Node)与集群(Cluster)
Elastic 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。
单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。
2. 索引(Index)
Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。
所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它可看作是单个数据库。每个 Index 的名字必须是小写。
下面的请求可以查看当前节点的所有 Index。
RQ:
GET localhost:9200/_cat/indices?v
RS:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open school Hlo2I4KlQU-uLqjw-lDq6g 1 1 2 1 11.7kb 11.7kb
上述RS中有一个索引school
。
3. 文档(Document)
Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。
Document 使用 JSON 格式表示,下面是一个例子。
{
"id": "1",
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生"
}
同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。
4. 类型(Type)
Document 可以分组,比如school
这个Index 里面,可以按教师分组,也可以按学生分组。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document。
不同的 Type 应该有相似的结构(schema),举例来说,id字段不能在这个组是字符串,在另一个组是数值。这是与关系型数据库的表的一个区别。性质完全不同的数据(比如products和logs)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)。
下面的命令可以列出每个 Index 所包含的 Type。
RQ:
GET localhost:9200/_mapping?pretty=true
RS:
{
"school": {
"mappings": {}
}
}
根据elastic官网规划,Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。
三、Index操作
1. 添加 Index
向Elastic服务器发送PUT请求:
RQ:
PUT localhost:9200/school
RS:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "school"
}
服务器返回一个 JSON 对象,里面的acknowledged
字段为true
表示添加成功。
2. 查看 Index
向Elastic服务器发送GET请求:
RQ:查看school这个Index
GET localhost:9200/school
RS:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "school"
}
RQ:查看当前实例中所有Index
GET localhost:9200/_cat/indices?v
RS:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open school XllA1jp4T9epF39e9uPwkw 1 1 0 0 208b 208b
3. 删除 Index
向Elastic服务器发送DELETE请求:
RQ:
DELETE localhost:9200/school
RS:
{
"acknowledged": true
}
三、数据操作
1. 添加数据
向Elastic服务器发送PUT请求,添加一条student数据,有id、name、age、desc
四个属性:
{
"id": "1",
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生"
}
该数据在school
这个Index下,属于student
这个Type,student的属性数据就是document,即请求模板为localhost:9200/index/type/{id}
。
RQ:
PUT localhost:9200/school/student/1
{
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生"
}
RS:
{
"_index": "school",
"_type": "student",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
服务器返回的 JSON 对象,会给出 Index、Type、Id、Version 等信息。
如果你仔细看,会发现请求路径是/school/student/1
,最后的1
是该条记录的 id
。它不一定是数字,任意字符串(比如abc
)都可以。
新增记录的时候,也可以不指定 id,但是这时要改成 POST 请求。
RQ:
POST localhost:9200/school/student
{
"name": "张三",
"age": 25,
"desc": "我是一名班级干部"
}
RS:
{
"_index": "school",
"_type": "student",
"_id": "EYamPXMBSJB2se0qHXyl",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
这时,服务器返回的 JSON 对象里面,_id
字段就是一个随机字符串。
注意,如果没有先创建 Index(这个例子是school),直接执行上面的命令,Elastic 也不会报错,而是直接生成指定的 Index。所以,打字的时候要小心,不要写错 Index 的名称。
2. 查看数据
向Elastic服务器发送GET请求:
RQ:
GET localhost:9200/school/student/1?pretty=true
RS:
{
"_index": "school",
"_type": "student",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生"
}
}
上面RQ代码中请求查看/school/student/1
这条记录,URL 的参数pretty=true
表示以易读的格式返回。
返回的数据RS中,found
字段为true
表示查询成功,_source
字段返回数据记录。
如果id不正确,就查不到数据,found
字段就是false
。例如下面的请求:
RQ:
GET localhost:9200/school/student/abc?pretty=true
RS:
{
"_index": "school",
"_type": "student",
"_id": "abc",
"found": false
}
3. 删除数据
向Elastic服务器发送DELETE请求:
RQ:
DELETE localhost:9200/school/student/1
RS:
{
"_index": "school",
"_type": "student",
"_id": "1",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
这里先不要删除这条记录,后面还要用到。
4. 更新数据
更新记录就是使用 PUT 请求,重新发送一次数据:
RQ:
PUT localhost:9200/school/student/1
{
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生也是一名班级干部"
}
RS:
{
"_index": "school",
"_type": "student",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}
上面RQ代码中,小编将原始数据从"我是一名三好学生
“改成”我是一名三好学生也是一名班级干部
"。 返回结果里面,有几个字段发生了变化。
可以看到,记录的 id 没变,但是版本(version)从1
变成2
,操作结果(result)从created
变成updated
。
在低版本的Elastic中更新操作返回的JSON里面有一个created
字段变成false
,因为这次不是新建记录。高版本的Elastic中删除了created
字段。
四、数据查询
1. 查询所有数据
向Elastic服务器发送GET请求:
RQ:
GET localhost:9200/school/student/_search
RS:
{
"took": 62,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "school",
"_type": "student",
"_id": "EYamPXMBSJB2se0qHXyl",
"_score": 1.0,
"_source": {
"name": "张三",
"age": 25,
"desc": "我是一名班级干部"
}
},
{
"_index": "school",
"_type": "student",
"_id": "1",
"_score": 1.0,
"_source": {
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生也是一名班级干部"
}
}
]
}
}
上面RS代码中,返回结果的took
字段表示该操作的耗时(单位为毫秒);timed_out
字段表示是否超时;hits
字段表示命中的记录,里面子字段的含义如下:
total:返回记录数,本例是2条。
max_score:最高的匹配程度,本例是1.0。
hits:返回的记录组成的数组。
返回的记录中,每条记录都有一个_score
字段,表示匹配的程度,默认是按照这个字段降序排列。
2. 全文搜索
Elastic 的查询要求 GET 请求带有数据体,更多请查看官方文档-全文查询。
2.1 Match 查询
RQ:Match 查询,指定的匹配条件是desc
字段里面包含"三好学生
"这个词。
GET localhost:9200/school/student/_search
{
"query": {
"match": {
"desc": "三好学生"
}
}
}
RS:
{
"took": 28,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.5607667,
"hits": [
{
"_index": "school",
"_type": "student",
"_id": "1",
"_score": 1.5607667,
"_source": {
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生也是一名班级干部"
}
}
]
}
}
Elastic 默认一次返回10
条结果,可以通过size
字段改变这个设置。
{
"query": {
"match": {
"desc": "三好学生"
}
},
"size": 5
}
还可以通过from
字段,指定位移。
{
"query": {
"match": {
"desc": "三好学生"
}
},
"from": 1,
"size": 5
}
from
和size
一起使用即为分页查询
,上述代码中从位置1开始(默认是从位置0开始),只返回5条结果。
3. 逻辑运算
3.1 OR运算
如果有多个搜索关键字, Elastic 认为它们是or
关系。
RQ:
GET localhost:9200/school/student/_search
{
"query": {
"match": {
"desc": "学生 干部"
}
}
}
RS:
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.5607667,
"hits": [
{
"_index": "school",
"_type": "student",
"_id": "1",
"_score": 1.5607667,
"_source": {
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生也是一名班级干部"
}
},
{
"_index": "school",
"_type": "student",
"_id": "EYamPXMBSJB2se0qHXyl",
"_score": 1.0470967,
"_source": {
"name": "张三",
"age": 25,
"desc": "我是一名班级干部"
}
}
]
}
}
上面RQ代码中搜索的是学生 or 干部
,中间有一个空格隔开。
下面这段RQ代码没有空格隔开也能查出两条数据:
RQ:
GET localhost:9200/school/student/_search
{
"query": {
"match": {
"desc": "学生干部"
}
}
}
RS:
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.5607667,
"hits": [
{
"_index": "school",
"_type": "student",
"_id": "1",
"_score": 1.5607667,
"_source": {
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生也是一名班级干部"
}
},
{
"_index": "school",
"_type": "student",
"_id": "EYamPXMBSJB2se0qHXyl",
"_score": 1.0470967,
"_source": {
"name": "张三",
"age": 25,
"desc": "我是一名班级干部"
}
}
]
}
}
这里就是分词查询
出来的结果,Elastic会将学生干部
分为若干个分词进行查询,其中就分为学生 or 干部
。
3.2 AND运算
如果要执行多个关键词的and搜索,必须使用布尔查询。
RQ:
GET localhost:9200/school/student/_search
{
"query": {
"bool": {
"must": [
{ "match": { "desc": "学生" } },
{ "match": { "desc": "干部" } }
]
}
}
}
RS:
{
"took": 15,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.5607667,
"hits": [
{
"_index": "school",
"_type": "student",
"_id": "1",
"_score": 1.5607667,
"_source": {
"name": "成应奎",
"age": 24,
"desc": "我是一名三好学生也是一名班级干部"
}
}
]
}
}
上面RQ代码中搜索的是学生 and 干部
,所以查询出来的结果只有一条数据。
五、官方文档
本博文仅供记录笔记,博文记录得不是很全,详情请移步至《ElasticSearch官方文档》。小编初次接触Elastic,若有什么写得不对的地方欢迎各位大佬留言。