ElasticSearch(上)——基础操作

什么是ElasticSearch?

在这里插入图片描述

Elasticsearch是一个分布式的免费开源搜索和分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。
Elasticsearch在Apache Lucene的基础上开发而成。然而,Elasticsearch不仅仅是Lucene,并且也不仅仅只是一个全文搜索引擎:

  • 一个分布式的实时文档存储,每个字段都可以被索引与搜索
  • 一个分布式实时分析搜索引擎
  • 能胜任上百个服务节点的扩展,并支持PB级别的结构化或者非结构化数据

所以Apache Lucene是什么?
Lucene是一套用于全文索引和搜索的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜索。但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)

Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎

在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆。

关于ELK

Elastic Stack是一套适用于数据采集、扩充、存储、分析和可视化的免费开源工具。人们通常将Elastic Stack称为ELK Stack(代指 Elasticsearch、Logstash 和 Kibana)
在这里插入图片描述
Logstash是什么?
Logstash 是 Elastic Stack 的核心产品之一,可用来对数据进行聚合和处理,并将数据发送到 Elasticsearch。Logstash 是一个开源的服务器端数据处理管道,允许您在将数据索引到 Elasticsearch 之前同时从多个来源采集数据,并对数据进行充实和转换。

Kibana是什么?
Kibana 是一款适用于Elasticsearch的数据可视化和管理工具,可以提供实时的直方图、线形图、饼状图和地图。Kibana同时还包括诸如 Canvas和Elastic Maps等高级应用程序。

  • Canvas允许用户基于自身数据创建定制的动态信息图表

  • Elastic Maps用来对地理空间数据进行可视化。
    在这里插入图片描述
    Elasticsearch的特点

  • Elasticsearch 很快。 由于Elasticsearch是在Lucene基础上构建而成的,所以在全文本搜索方面表现十分出色。Elasticsearch同时还是一个近实时的搜索平台,这意味着从文档索引操作到文档变为可搜索状态之间的延时很短,一般只有一秒。因此,Elasticsearch 非常适用于对时间有严苛要求的用例,例如安全分析和基础设施监测。

  • Elasticsearch 具有分布式的本质特征。 Elasticsearch中存储的文档分布在不同的容器中,这些容器称为分片,可以进行复制以提供数据冗余副本,以防发生硬件故障。Elasticsearch的分布式特性使得它可以扩展至数百台(甚至数千台)服务器,并处理 PB 量级的数据。

  • Elasticsearch 包含一系列广泛的功能。 除了速度、可扩展性和弹性等优势以外,Elasticsearch 还有大量强大的内置功能(例如数据汇总和索引生命周期管理),可以方便用户更加高效地存储和搜索数据。

  • Elastic Stack 简化了数据采集、可视化和报告过程。 通过与 Beats 和 Logstash 进行集成,用户能够在向 Elasticsearch 中索引数据之前轻松地处理数据。同时,Kibana 不仅可针对 Elasticsearch 数据提供实时可视化,同时还提供 UI 以便用户快速访问应用程序性能监测 (APM)、日志和基础设施指标等数据。

ES应用场景

Elasticsearch在速度和可扩展性方面都表现出色,而且还能够索引多种类型的内容,这意味着其可用于多种用例:

应用程序搜索 网站搜索 企业搜索 日志处理和分析 基础设施指标和容器监测 应用程序性能监测 地理空间数据分析和可视化 安全分析 业务分析

架构设计

在这里插入图片描述

  • Gateway:Elasticsearch用来存储索引的文件系统,支持多种类型。ElasticSearch默认先把索引存储在内存中,然后当内存满的时候,再持久化到Gateway里。当ES集群关闭或重启的时候,它就会从Gateway里去读取索引数据。比如LocalFileSystem和HDFS、AS3等。
  • DistributedLucene Directory:Lucene里的一些列索引文件组成的目录。它负责管理这些索引文件。包括数据的读取、写入,以及索引的添加和合并等。
  • Mapping:映射解析模块。
  • Search Moudle:搜索模块。
  • Index Moudle:索引模块。
  • Disvcovery:节点发现模块。不同机器上的节点要组成集群需要进行消息通信,集群内部需要选举master节点,这些工作都是由Discovery模块完成。支持多种发现机制,如 Zen 、EC2、gce、Azure。
  • Scripting:Scripting用来支持在查询语句中插入javascript、python等脚本语言。
  • 3rd plugins:第三方插件。
  • Transport:传输模块,支持多种传输协议,如 Thrift、memecached、http,默认使用http。
  • JMX:JMX是java的管理框架,用来管理ES应用。
  • Java(Netty):java的通信框架。
  • RESTful Style API:提供给用户的接口,通过RESTful方式来实现API编程。

ES基本概念

Elasticsearch是一个文档型数据库,为了方便理解,下面给出其与传统的关系型数据库的对比

Relational DBElasticsearch
数据库 Database索引 Index
表 Table类型 Type
行 Rows文档 Document
列 columns字段 fields
表结构 schema映射 mapping

上面之所以说一个索引是一个库是因为传统的关系型数据库里面一个库下的表直接是互相有关系的,但是es这里是相互独立的没有联系的,所以最终可以理解es这个里面有各种互相独立的表,这个表下面的mappings就是所有的表的字段结构。

在这里插入图片描述
注意:text类型在查找的时候会分词,keyword不会,比如hello world这个字符串,在查找的时候,他会被分为 hello、world两个term,搜索这两个任意一个都能查到这个数据,但是用这个字段的keyword属性他就是一个整体,只有搜索完整的才查的到,所以在上面,每个字段后面又多一个一个field就可以理解为一个子属性。

文档

Elasticsearch是面向文档的,索引和搜索数据的最小单位是文档,并且使用JSON来作为文档的序列化格式。每个文档可以由一个或多个字段组成,类似于关系型数据库中的一行记录,在Elasticsearch中,文档有几个重要属性

  • 自我包含:一篇文档同时包含字段和对应的值。
  • 层次型:文档中还可以包含新的文档,一个字段的取值也可以包含其他字段和取值。
  • 结构灵活:文档不依赖预先定义的模式。在关系型数据库中,要提前定义字段才能使用,在Elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。
    尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整形。因为Elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型,这也是为什么在Elasticsearch中,类型有时候也称为映射类型。

类型

类型是文档的逻辑容器,类似于表格是行的容器。在不同的类型中,最好放入不同结构的文档。(有点类似于关系型数据库中的表的概念)。
ElasticSearch要在7.X版本去掉type
在Elasticsearch设计初期,是直接查考了关系型数据库的设计模式,存在了类型(表)的概念。 但是,其搜索引擎是基于Lucene的,这种基因决定了类型是多余的。Lucene的全文检索功能之所以快,是因为倒序索引的存在。 而这种倒序索引的生成是基于索引的,而并非 类型。多个类型反而会减慢搜索的速度——两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。

索引

在Elasticsearch中,索引有两个含义:

  • 名词
    索引是映射类型的容器,Elasticsearch中的索引是一个非常大的文档集合,非常类似关系型数据库中库的概念。索引存储了所有映射类型的字段。
  • 动词
    索引一个文档就是存储一个文档到一个索引 (名词)中以便被检索和查询。这非常类似于SQL中的INSERT关键词,不同的是文档已存在时,新文档会替换旧文档(UPSERT)。
    在Elasticsearch中,索引使用了一种称为倒排索引(即通过查询词索引到文档)的结构,它适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。

基本操作

搭建Elasticsearch环境

下载docker镜像

docker pull elasticsearch:7.10.2

映射配置文件

# 配置映射文件夹
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data

# 设置文件夹权限任何用户可读可写
chmod 777 /mydata/elasticsearch -R

# 配置 http.host
echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
Copy

启动容器

docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e "discovery.type"="single-node" \	 # 设置为单节点
-e ES_JAVA_OPTS="-Xms64m -Xmx128m" \ # 设置启动时ES的初始内存以及最大内存
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.10.2

访问ES服务,http://ip:9200/
得到相应体如下:

{
  "name" : "de85ed684243",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "UeIP1PrXT2OFd7FlEEl3hQ",
  "version" : {
    "number" : "7.4.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
    "build_date" : "2019-10-28T20:40:44.881551Z",
    "build_snapshot" : false,
    "lucene_version" : "8.2.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

可以通过/_cat来获取节点信息

# 访问http://ip:9200/_cat
# 属性列表
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/tasks
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/thread_pool/{thread_pools}
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
/_cat/nodeattrs
/_cat/repositories
/_cat/snapshots/{repository}
/_cat/templates

搭建Kibana环境

下载docker镜像

docker pull kibana:7.4.2

启动容器

docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.0.128:9200 -p 5601:5601 -d kibana:7.4.2

CRUD

ES的基本REST命令:

MethodUrl描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
GETlocalhost:9200/索引名称/类型名称/文档id通过文档id查询文档
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档

创建索引
在创建索引时,我们可以声明字段与数据类型的映射
请求:

PUT /test0
{
    "mappings":{
        "properties":{
            "name":{
                "type":"text"
            },
            "author":{
                "type":"text"
            }
        }
    }
}

响应:

{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "test0"
}

注意⚠️:由于索引具有不变性,我们只能进行追加而不能更改已经存在的映射字段,必须创建新的索引后进行数据迁移。

POST _reindex
{
  "source": {
    "index": "test0"
  },
  "dest": {
    "index": "test1"
 }
}

插入文档
PUT和POST都可以插入文档:

  • POST:如果不指定 id,自动生成 id。如果指定 id,则修改这条记录,并新增版本号。
  • PUT:必须指定 id,如果没有这条记录,则新增,如果有,则更新。
    示例:在 test1 索引下的books类型中保存标识为 1 的文档。
    请求:
PUT /test1/books/1
{
	"name":"three days to see",
  "author" : "Daniel Defoe"
}

响应:

{
    "_index": "test",			//索引
    "_type": "book",			//类型
    "_id": "1",						//id
    "_version": 1,				//版本号
    "result": "updated",	//操作类型
    "_shards": {					//分片
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,					//并发控制字段,每次更新就会+1,用来做乐观锁
    "_primary_term": 1    //同上,主分片重新分配,如重启,就会变化
}

查询文档
示例:查询test1索引下的books类型中保存标识为 1 的文档的内容。
请求:

GET /test1/books/1

响应:

{
    "_index": "test1",
    "_type": "books",
    "_id": "1",
    "_version": 1,
    "_seq_no": 0,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "name": "three days to see",
        "author": "Daniel Defoe"
    }
}

更新文档
使用POST命令,在ID后面加_update,并把需要修改的内容放入doc属性中
示例:更新test1 索引下的books类型中保存标识为 1 的文档的内容。
请求:

POST /test1/books/1/_update
{
	"doc" : {
		"name":"three days to see",
  	"author" : "Daniel Defoe",
  	"country" : "England"
	}
}

响应:

{
    "_index": "test1",
    "_type": "books",
    "_id": "1",
    "_version": 2,
    "result": "updated",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,
    "_primary_term": 1
}

删除文档和索引
删除使用DELETE命令
示例:删除文档/test1/books/1
请求:

DELETE /test1/books/1

响应:

{
    "_index": "test1",
    "_type": "books",
    "_id": "1",
    "_version": 3,
    "result": "deleted",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
}

示例:删除索引/test1

DELETE /test1

响应:

{
    "acknowledged": true
}

查询

查询方式
ES支持两种查询方式,一种是直接在URL后加上参数,另一种是在URL后加上JSON格式的请求体。
示例:查找到收入最高的十条记录
URL + 参数
常用的参数如下

  • q:用于指定搜索的关键词。
  • from & size:类似于SQL中的offset和limit。
  • sort:对结果排序,默认为降序。
  • _source:指定想要返回的属性。
GET /test_data/_search?q=*&sort=balance:desc&from=0&size=10

URL + QueryDSL

GET /test_data/_search
{
    "query": {
        "match_all" : {} 
    },
    "sort" : [{
    		"balance" : "desc"
    }],
    "from" : 0,
    "size" : 10
}

虽然URL+参数的写法非常简洁,但是随着逻辑的复杂化,其可读性也越来越差,所以通常都会使用URL + QueryDSL的格式。

match 匹配

无论你在任何字段上进行的是全文搜索还是精确查询,match 查询是你可用的标准查询。

对于not_analyzed的字段,match能做到精确查询,而对于analyzed的字段,match能做到匹配查询(全文搜索)。
示例:查找所有年龄为25岁的记录(精确查询)

GET /test_data/_search
{
    "query":{
        "match" : {
        	"age": 25
        } 
    }
}

示例:查询所有地址与976 Lawrence Street相关的记录(全文搜索)

GET /test_data/_search
{
    "query":{
        "match" : {
        	"address": "976 Lawrence Street"
        } 
    }
}

match_all 全部匹配
match_all 用于查询所有文档。在没有指定查询方式时,它是默认。
示例:查询年龄最小的十条记录
请求:

GET /test_data/_search
{
    "query": {
        "match_all" : {} 
    },
    "sort" : [{
    		"age" : "asc"
    }],
    "from" : 0,
    "size" : 10
}

match_phase 短语匹配
match_phase用于进行短语的匹配,它查询时并不是像term一样不进行分词直接查询,而是借助分析器返回的查询词的相对顺序以及偏移量来做判断——满足所有查询词且顺序完全相同的记录才会被匹配上。

示例:地址包含502 Baycliff Terrace的记录

GET /test_data/_search
{
    "query":{
        "match_phase" : {
        	"address": "502 Baycliff Terrace"
        } 
    }
}

multi_match 多字段匹配
multi_match 可以在多个字段上执行相同的 match 查询。

示例:查找city或address字段中包含Dixie或Street的记录。

请求:

GET /test_data/_search
{
    "query":{
        "multi_match":{
            "query":"Dixie Street",
            "fields":[
                "city",
                "address"
            ]
        }
    }
}

term 精确查询

term即直接在倒排索引中查询,也就是精确查找,不进行分词器分析,文档中必须包含整个搜索的词汇。
term和match的区别:

  • match是经过分析处理的,查询词先被文本分析器处理后再进行查询。所以根据不同的文本分析器,分析出的结果也会不同。
  • term是不经过分析处理的,直接去倒排索引查找精确的值。
    由于text字段会被文本分析器处理,所以通常全文检索字段用match,其他非text字段(not_analyzed)匹配用term。
GET /test_data/_search
{
  "query": {
    "term": {
      "address": "Street"
    }
  }
}

// 虽然文档中存在”702 Quentin Street“,但是由于文本分析器默认会转为小写,无法搜到任何数据

布尔查询(复合查询)

借助布尔查询可以实现如SQL中(and、or、!=)等逻辑条件的判断,并且可以合并任何其他查询语句,包括复合语句。复合语句之间可以相互嵌套,可以表达复杂的逻辑。

  • must(and):文档必须匹配这些条件才能被包含进来。(影响相关性得分)

  • must_not(not):文档必须不匹配这些条件才能被包含进来。(不影响相关性得分)

  • should(or):如果满足这些语句中的任意语句,将增加得分 。(用于修正相关性得分)
    示例:查找年龄不等于18的地址包含Street的男性,且优先展示居住在30岁以上的的记录

GET /test_data/_search
{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "address":"Street"
                    }
                },
                {
                    "match":{
                        "gender":"M"
                    }
                }
            ],
            "must_not":[
                {
                    "match":{
                        "age":"18"
                    }
                }
            ],
            "should":[
                {
                    "range":{
                        "age":{
                            "gt":30
                        }
                    }
                }
            ]
        }
    }
}

Filter 过滤器

Filter通常搭配布尔查询一起使用,用于过滤出所有满足Filter的记录,不影响相关性得分。

示例:查找年龄在30~60之间的记录

GET /test_data/_search
{
    "query":{
        "bool":{
            "filter":[
                {
                    "range":{
                        "age":{
                            "gte":30,
                            "lte":60
                        }
                    }
                }
            ]
        }
    }
}

Aggregations 聚合

要掌握聚合,需要明白两个主要的概念:

桶(Buckets):满足特定条件的文档的集合
指标(Metrics):对桶内的文档进行统计计算

SELECT 
	COUNT(1),
  MAX(balance)
FROM table
GROUP BY gender;

桶在概念上类似于 SQL 的分组(GROUP BY,如上面的GROUP BY gender),而指标则类似于 COUNT() 、 SUM() 、 MAX() 等统计方法,如MAX(balance)。
聚合的语法如下:

"aggregations" : {
    "<聚合名称 1>" : {
        "<聚合类型>" : {
            <聚合体内容>
        }
        [,"元数据" : {  [<meta_data_body>] }]?
        [,"aggregations" : { [<sub_aggregation>]+ }]?
    }
    ["聚合名称 2>" : { ... }]*
}

示例:按照性别进行分组,计算平均年龄和最高收入

GET /test_data/_search
{
    "query":{
        "match_all": {}
    },
    "aggs":{
        "group_gender":{
            "terms":{
                "field":"gender"
            },
            "aggs":{
                "avg_age":{
                    "avg":{
                        "field":"age"
                    }
                },
                "max_balance":{
                    "max":{
                        "field":"balance"
                    }
                }
            }
        }
    },
    "size":0
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值