来源 黑马讲义
目录
1. ElasticStack 简介
2. ElasticSearch简介
3. 安装
3.1 window / linux 安装
3.2 Docker安装
4. elasticsearch-head
5. 基本概念
6. RESTful API
6.1 创建非结构化索引
7. 核心讲解
7.1 文档
7.2 pretty
7.3 指定响应对象
7.4 判断文档是否存在
7.5 批量操作
7.5.1 批量查询
7.5.2 _bulk操作
7.6 分页
7.7 映射
7.8 结构化查询
7.8.1 term查询
7.8.2 terms查询
7.8.3 range查询
7.8.4 exists 查询
7.8.5 match查询
7.8.6 bool查询
7.8.7 过滤查询
8. 中文分词
8.1 什么是分词
8.2 分词api
8.3 内置分词
8.3.1 Standard
8.3.2 Simple
8.3.3 Whitespace
8.3.3 Stop
8.3.4 Keyword
8.4 中文分词
如果你没有听说过Elastic Stack,那你一定听说过ELK,实际上ELK是三款软件的简称,分别是Elasticsearch、
Logstash、Kibana组成,在发展的过程中,又有新成员Beats的加入,所以就形成了Elastic Stack。所以说,ELK
是旧的称呼,Elastic Stack是新的名字。
全新的的ElasticStack包括
Beats组成
ElasticSearch是一个基于lucene的搜索服务器、他提供了一个分布式多用户能力的全文搜索引擎,基于RestFul Web接口。ElasticSearch是基于Java开发的,并作为Apache许可条款下的开放源代码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定、可靠、快速、安装使用方便。
官网:https://www.elastic.co/cn/products/elasticsearch
下载地址 https://www.elastic.co/cn/downloads/past-releases/elasticsearch-6-5-4
官网太慢了 使用百度网盘 如果下载还是慢 就充钱吧 没有什么是充钱解决不了的事 如果解决不了 那就多冲点
链接:https://pan.baidu.com/s/1uGajQ5n6zqFmix3xhIQSKQ
提取码:c2j3
3.1.1 编辑config / elasticsearch.yml
将network.host改为 127.0.0.1
注意看注释、看到下面就可以猜出来 http.port是指定es的http端口的
3.1.2 编辑 config / jvm.options
找到如上,改为上图中的值
3.1.3 启动
3.1.4 测试
浏览器访问 127.0.0.1:9200 如图成功
#拉取镜像
docker pull elasticsearch:6.5.4
#创建容器
docker create --name elasticsearch --net host -e "discovery.type=single-node" -e
"network.host=172.16.55.185" elasticsearch:6.5.4
#启动
docker start elasticsearch
#查看日志
docker logs elasticsearch
自行测试
官方没有提供es的图形化管理工具,elasticsearch-head是为es开发的一个页面客户端工具
官方地址 https://github.com/mobz/elasticsearch-head
windows安装 https://www.cnblogs.com/hts-technology/p/8477258.html
docker安装
#拉取镜像
docker pull mobz/elasticsearch-head:5
#创建容器
docker create --name elasticsearch-head -p 9100:9100 mobz/elasticsearch-head:5
#启动容器
docker start elasticsearch-head
索引
文档
映射
文档类型
6.1.1 创建空索引
PUT http://172.16.55.185:9200/haoke
{
"settings": {
"index": {
"number_of_shards": "2", #分片数
"number_of_replicas": "0" #副本数
}
}
}
#删除索引
DELETE http://172.16.55.185:9200/haoke
{
"acknowledged": true
}
6.1.2 插入数据
POST http://172.16.55.185:9200/{索引}/{类型}/{id}
POST http://172.16.55.185:9200/haoke/user/1001
#数据
{
"id":1001,
"name":"张三",
"age":20,
"sex":"男"
}
#响应
{
"_index": "haoke",
"_type": "user",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
6.1.3 更新数据
PUT http://172.16.55.185:9200/haoke/user/1001
{
"id":1001,
"name":"张三",
"age":21,
"sex":"女"
}
6.1.4 局部更新
#注意:这里多了_update标识
POST http://172.16.55.185:9200/haoke/user/1001/_update
{
"doc":{
"age":23
}
}
6.1.5 删除数据
DELETE http://172.16.55.185:9200/haoke/user/1001
6.2 搜索数据
6.2.1 根据id搜索数据
GET http://172.16.55.185:9200/haoke/user/BbPe_WcB9cFOnF3uebvr
6.2.2 搜索全部数据
GET http://172.16.55.185:9200/haoke/user/_search
6.2.3 关键字搜素数据
#查询年龄等于20的用户
GET http://172.16.55.185:9200/haoke/user/_search?q=age:20
6.3 DSL搜索
Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。
DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。
6.3.1 查询年龄大于30岁的男性用户
POST http://172.16.55.185:9200/haoke/user/_search
#请求数据
{
"query": {
"bool": {
"filter": {
"range": {
"age": {
"gt": 30
}
}
},
"must": {
"match": {
"sex": "男"
}
}
}
}
}
6.3.2 全文搜索
POST http://172.16.55.185:9200/haoke/user/_search
#请求数据
{
"query": {
"match": {
"name": "张三 李四"
}
}
}
6.4 高亮显示
POST http://172.16.55.185:9200/haoke/user/_search
{
"query": {
"match": {
"name": "张三 李四"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
6.5 聚合
POST http://172.16.55.185:9200/haoke/user/_search
{
"aggs": {
"all_interests": {
"terms": {
"field": "age"
}
}
}
}
在Elasticsearch中,文档以JSON格式进行存储,可以是复杂的结构,如:
{
"_index": "haoke",
"_type": "user",
"_id": "1005",
"_version": 1,
"_score": 1,
"_source": {
"id": 1005,
"name": "孙七",
"age": 37,
"sex": "女",
"card": {
"card_number": "123456789"
}
}
}
其中,card是一个复杂对象,嵌套的Card对象。
元数据(metadata)
可以在查询url后面添加pretty参数,使得返回的json更易查看。
在响应的数据中,如果我们不需要全部的字段,可以指定某些需要的字段进行返回。
GET http://172.16.55.185:9200/haoke/user/1005?_source=id,name
#响应
{
"_index": "haoke",
"_type": "user",
"_id": "1005",
"_version": 1,
"found": true,
"_source": {
"name": "孙七",
"id": 1005
}
}
如不需要返回元数据,仅仅返回原始数据,可以这样:
GET http://172.16.55.185:9200/haoke/user/1005/_source
还可以这样:
GET http://172.16.55.185:9200/haoke/user/1005/_source?_source=id,name
如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样:
HEAD http://172.16.55.185:9200/haoke/user/1005
POST http://172.16.55.185:9200/haoke/user/_mget
{
"ids" : [ "1001", "1003" ]
}
在Elasticsearch中,支持批量的插入、修改、删除操作,都是通过_bulk的api完成的。
请求格式如下:(请求格式不同寻常)
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
批量插入数据:
{"create":{"_index":"haoke","_type":"user","_id":2001}}
{"id":2001,"name":"name1","age": 20,"sex": "男"}
{"create":{"_index":"haoke","_type":"user","_id":2002}}
{"id":2002,"name":"name2","age": 20,"sex": "男"}
{"create":{"_index":"haoke","_type":"user","_id":2003}}
{"id":2003,"name":"name3","age": 20,"sex": "男"}
注意最后一行的回车
批量删除:
{"delete":{"_index":"haoke","_type":"user","_id":2001}}
{"delete":{"_index":"haoke","_type":"user","_id":2002}}
{"delete":{"_index":"haoke","_type":"user","_id":2003}}
由于delete没有请求体,所以,action的下一行直接就是下一个action。
其他操作就类似了。
一次请求多少性能最高?
如果你想每页显示5个结果,页码从1到3,那请求如下:
# size: 结果数,默认10
# from: 跳过开始的结果数,默认0
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10
应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个
分片。每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确。
在集群系统中深度分页
为了理解为什么深度分页是有问题的,让我们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一
页(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),它
再排序这所有的50个结果以选出顶端的10个结果。
现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端
的10010个结果。然后请求节点排序这50050个结果并丢弃50040个!你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任
何语句不能返回多于1000个结果的原因。
前面我们创建的索引以及插入数据,都是由Elasticsearch进行自动判断类型,有些时候我们是需要进行明确字段类
型的,否则,自动判断的类型和实际需求是不相符的。
自动判断的规则如下:
Elasticsearch中支持的类型如下:
- string类型在ElasticSearch 旧版本中使用较多,从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。
- text 类型,当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。
- keyword类型适用于索引结构化的字段,比如email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合。keyword类型的字段只能通过精确值搜索到。
创建明确类型的索引:
PUT http://172.16.55.185:9200/itcast
{
"settings": {
"index": {
"number_of_shards": "2",
"number_of_replicas": "0"
}
},
"mappings": {
"person": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "integer"
},
"mail": {
"type": "keyword"
},
"hobby": {
"type": "text"
}
}
}
}
}
查看映射:
GET http://172.16.55.185:9200/itcast/_mapping
# 127.0.0.1:9200/purchaseinfo/purchaseinfo/_mapping?pretty
{
"purchaseinfo":{
"properties": {
"title": {
"type": "text"
},
"type": {
"type": "text"
},
"region": {
"type": "text"
},
"industry": {
"type": "text"
},
"detail": {
"type": "text"
},
"createDate": {
"type": "text"
}
}
}
}
term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):
POST http://172.16.55.185:9200/itcast/person/_search
{
"query" : {
"term" : {
"age" : 20
}
}
}
terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一
起去做匹配:
POST http://172.16.55.185:9200/itcast/person/_search
{
"query" : {
"terms" : {
"age" : [20,21]
}
}
}
range 过滤允许我们按照指定范围查找一批数据
{
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}
POST http://172.16.55.185:9200/itcast/person/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 22
}
}
}
}
exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件
POST http://172.16.55.185:9200/haoke/user/_search
{
"query": {
"exists": { #必须包含
"field": "card"
}
}
}
match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符
如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索
你给定的值
{ "match": { "age": 26 }}
{ "match": { "date": "2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "tag": "full_text" }}
bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符
这些参数可以分别继承一个查询条件或者一个查询条件的数组:
{
"bool": {
"must": { "term": { "folder": "inbox" }},
"must_not": { "term": { "tag": "spam" }},
"should": [
{ "term": { "starred": true }},
{ "term": { "unread": true }}
]
}
}
前面讲过结构化查询,Elasticsearch也支持过滤查询,如term、range、match等。
示例:查询年龄为20岁的用户。
POST http://172.16.55.185:9200/itcast/person/_search
{
"query": {
"bool": {
"filter": {
"term": {
"age": 20
}
}
}
}
}
查询和过滤的对比
建议:
做精确匹配时,最好用过滤语句,因为过滤语句可以缓存结果
词就是指将一个文本转化成一系列单词的过程,也叫文本分析,在Elasticsearch中称之为Analysis。
举例:我是中国人 --> 我/是/中国人
指定分词器进行分词
POST http://172.16.55.185:9200/_analyze
{
"analyzer":"standard",
"text":"hello world"
}
指定索引分词
POST http://172.16.55.185:9200/itcast/_analyze
{
"analyzer": "standard",
"field": "hobby",
"text": "听音乐"
}
Standard 标准分词,按单词切分,并且会转化成小写
POST http://172.16.55.185:9200/_analyze
{
"analyzer": "standard",
"text": "A man becomes learned by asking questions."
}
Simple分词器,按照非单词切分,并且做小写处理
结果
{
"tokens": [
{
"token": "if",
"start_offset": 0,
"end_offset": 2,
"type": "word",
"position": 0
},
{
"token": "the",
"start_offset": 3,
"end_offset": 6,
"type": "word",
"position": 1
},
{
"token": "document",
"start_offset": 7,
"end_offset": 15,
"type": "word",
"position": 2
},
{
"token": "doesn",
"start_offset": 16,
"end_offset": 21,
"type": "word",
"position": 3
},
{
"token": "t",
"start_offset": 22,
"end_offset": 23,
"type": "word",
"position": 4
},
{
"token": "already",
"start_offset": 24,
"end_offset": 31,
"type": "word",
"position": 5
}
Whitespace是按照空格切分
POST http://172.16.55.185:9200/_analyze
{
"analyzer": "whitespace",
"text": "If the document doesn't already exist"
}
结果
{
"tokens": [
{
"token": "If",
"start_offset": 0,
"end_offset": 2,
"type": "word",
"position": 0
},
{
"token": "the",
"start_offset": 3,
"end_offset": 6,
"type": "word",
"position": 1
},
{
"token": "document",
"start_offset": 7,
"end_offset": 15,
"type": "word",
"position": 2
},
{
"token": "doesn't",
"start_offset": 16,
"end_offset": 23,
"type": "word",
Stop分词器,是去除Stop Word语气助词,如the、an等。
"analyzer": "stop"
结果
{
"tokens": [
{
"token": "document",
"start_offset": 7,
"end_offset": 15,
"type": "word",
"position": 2
},
{
"token": "doesn",
"start_offset": 16,
"end_offset": 21,
"type": "word",
"position": 3
},
{
"token": "t",
"start_offset": 22,
"end_offset": 23,
"type": "word",
"position": 4
},
{
"token": "already",
"start_offset": 24,
"end_offset": 31,
"type": "word",
"position": 5
},
{
"token": "exist",
"start_offset": 32,
"end_offset": 37,
"type": "word",
"position": 6
}
]
}
Keyword分词器,意思是传入就是关键词,不做分词处理
"analyzer": "keyword"
结果
{
"tokens": [
{
"token": "If the document doesn't already exist",
"start_offset": 0,
"end_offset": 37,
"type": "word",
"position": 0
}
]
}
中文分词的难点在于,在汉语中没有明显的词汇分界点,如在英语中,空格可以作为分隔符,如果分隔不正确就会
造成歧义。
常用中文分词器,IK、jieba、THULAC等,推荐使用IK分词器
IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,
IKAnalyzer已经推出了3个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析
算法的中文分词组件。新版本的IK Analyzer 3.0则发展为面向Java的公用分词组件,独立于Lucene项目,同
时提供了对Lucene的默认优化实现。
采用了特有的“正向迭代最细粒度切分算法“,具有80万字/秒的高速处理能力 采用了多子处理器分析模式,支
持:英文字母(IP地址、Email、URL)、数字(日期,常用中文数量词,罗马数字,科学计数法),中文词
汇(姓名、地名处理)等分词处理。 优化的词典存储,更小的内存占用。
IK分词器 Elasticsearch插件地址:https://github.com/medcl/elasticsearch-analysis-ik
安装方法:将下载到的elasticsearch-analysis-ik-6.5.4.zip解压到/elasticsearch/plugins/ik 目录下即可