0. 引言
这里源于工作中的需要,需要对历史数据进行记录,并基于此进行一个查重操作。
最终的方案确定为通过维护一个es数据表来进行历史数据的一个记录以及查询操作。
但是,我却不会相关的es数据库操作,因此,也是花了一两天在工作中初步学习了一下es数据库的基础使用方法。
因此,这里就大致梳理一下es数据库使用的一些基础知识,也算是对于我自己的一个知识积累吧。
当然,由于我本人并不是做数据库的,因此对于其中很多的内容理解仅仅只停留在使用的层面,对于es数据库本质的理解是几乎完全苍白的,仅仅通过参考链接中的一些博客或者官方文档有一定的粗浅的理解而已。
如果有读者想要在这一领域内深耕的话,还是请以参考链接中的官方文档为主进行学习。
1. es数据库入门
1. es简介
es数据库是在sql数据库之后新提出的一种非关系型数据库,它支持对于全文内容的索引,因此可以支持对于其中存储的数据的非完全匹配方式的快速搜索。
2. es安装与启动
我们基于官网的引导在本地尝试一下es数据库以及kibana的安装与使用。
这部分内容事实上官网上的内容是比较明确的,可以参考下述链接中的步骤进行安装和启动即可:
- https://www.elastic.co/cn/start
在安装完相应的安装包之后,我们只需要运行下述命令即可启动es
代码语言:javascript复制bin/elasticsearch
启动elasticsearch之后界面上会显示一个外部访问的ip,默认为http://127.0.0.1:9200
,在浏览器上打入这个ip就可以查看当前的elasticsearch的状态。
3. kibana简介
kibana为官方配套的一个针对es数据库的可视化数据查看工具。
我们同样像es那样先下载kibana,解压之后运行下述命令即可启动kibana:
代码语言:javascript复制bin/kibana
同样的,启动了kibana之后命令窗口中也会给出一个外部访问ip(默认为http://127.0.0.1:5601/
),在浏览器中输入即可对数据表进行查看。
我们可以在dev工具当中直接测试es库的请求命令(如下图所示):
我们也可以直接在kibana的dev tools
当中去检索当前数据库中的数据表(如下图所示):
当然,每一张es库中的表格需要先在kibana当中进行注册,这一点可以通过上图中的create index pattern
方法进行添加,但是直接在dev tools
进行操作的话就不需要了,可以直接进行访问。
2. es数据库使用基础
es数据库使用的基本逻辑就是:
- 使用elasticsearch库通过host ip连接es数据库;
- 通过表名(index_name)定位到es数据库中某张具体的表,然后对数据进行操作。
给出基础的操作样例如下:
代码语言:javascript复制from elasticsearch import Elasticsearch
HOST = '127.0.0.1:9200' # es数据库ip
es = Elasticsearch([HOST]) # 连接到es数据库
index_name = "my_es_table" # 对应的表名
# 查询
es.search(index=index_name, body=query, doc_type="sources")
# 数据插入
es.index(index=index_name, doc_type="sources", body=data)
# 数据删除
es.delete_by_query(index=index_name, body=query, doc_type="sources")
下面,我们就来考察一下有关这些操作的具体内容。
3. es表格创建 & 删除
1. es表格的创建
首先,我们来考察一下es中表格的创建过程。
在es中创建一张表格,大致需要做的内容包括:
- 指定表格的表明;
- 指定表格的结构;
- 发送命令到es进行表格的创建。
这里,我们重点来介绍一下表格的结构定义语法。
对一张es表格的表格定义,采用json格式的语法,一个典型的示例如下:
代码语言:javascript复制{
"mappings": {
"sources": {
"properties": {
"date": {
"type": "date"
},
"name": {
"type": "keyword",
"fields": {
"text": {
"type": "text",
"analyzer": "jieba_index"
}
}
},
"age":{
"type": "integer"
},
"gender":{
"type": "keyword"
},
"department": {
"type": "text"
}
}
}
}
}
其中,mappings
、sources
以及properties
为常备字段,下述date
、name
、age
、gender
以及apartment
字段为表格的索引字段,是可以自行设置的,每一个索引都通过一个字典的形式进行赋值,需要通过type
字段给定其类型特征。如果需要给出其他一些特征,则可以通过fields
字段来额外给出,比如上述例子当中,就是为了让name
字段即可以以keyword
的形式完全匹配,又可以通过text
的方式进行模糊匹配。
因此,我们即可在kibana上面发送下述命令即可创建一张表格:
代码语言:javascript复制PUT my_test_table
{
"mappings": {
"sources": {
"properties": {
"date": {
"type": "date"
},
"name": {
"type": "keyword",
"fields": {
"text": {
"type": "text",
"analyzer": "jieba_index"
}
}
},
"age":{
"type": "integer"
},
"gender":{
"type": "keyword"
},
"department": {
"type": "text"
}
}
}
}
}
需要说明的是,如果使用的elasticsearch版本高于7的话,貌似sources
字段已经不需要再提供了,mapping的定义方式为:
{
"mappings": {
"properties": {
"date": {
"type": "date"
},
"name": {
"type": "keyword"
},
"age":{
"type": "integer"
},
"gender":{
"type": "keyword"
},
"department": {
"type": "text"
}
}
}
}
具体关于es表中数据的数据类型可以参考下述链接中的说明:
- ES 15 - Elasticsearch的数据类型 (text、keyword、date、object、geo等)
当然,创建完成之后我们也可以通过下述命令来查看数据格式定义mapping内容:
代码语言:javascript复制GET my_test_table/_mapping
2. es表格的删除
而es表格的删除命令就更加简单了,只需要在kibana当中简单地输入下述命令即可删除对应的表格(my_test_table
):
DELETE my_test_table
4. es数据库写入数据
现在,我们来看一下如何向es数据库中写入数据。
1. 直接进行数据写入
首先,我们看一下如何在es当中直接进行数据的写入。
这部分内容其实就比较直接,只需要使用下述命令即可实现:
代码语言:javascript复制POST cys_test_table/sources
{
"name": "Alice",
"gender": "female",
"age": "24",
"department": "physics"
}
执行成功之后,数据库中会写入一条数据如下:
代码语言:javascript复制{
"_index": "cys_test_table",
"_type": "sources",
"_id": "K5GmOXgBCPJxWUBsP_1c",
"_score": 1,
"_source": {
"name": "Alice",
"gender": "female",
"age": "24",
"department": "physics"
}
}
其中,_id
字段为es表给该条数据分配的唯一id。如果有需要人工指定id的话,只需要将数据添加命令修改为如下即可:
POST cys_test_table/sources/123456
{
"name": "Bob",
"gender": "male",
"age": "24",
"department": "physics"
}
特别地:
- 如果两次数据上传时指定id相同,那么新的数据会直接覆盖掉原有的数据;
- 创建数据时可以允许数据中某一个字段为空;
2. python数据写入
下面,我们来考察一下如何使用python来对es数据库中的表格进行数据添加。
python向es表格中添加数据的方法主要基于elasticsearch库来实现。
1. 单条数据插入
python要实现单条数据的加入方法可以通过index
函数进行实现,其具体用法和上一节的内容并无差别。
给出一个简单的demo如下:
代码语言:javascript复制import datetime
from elasticsearch import Elasticsearch
HOST = '127.0.0.1:9200' # es数据库ip
es = Elasticsearch([HOST]) # 连接到es数据库
data = {
"name": "David",
"gender": "male",
"age": 30,
"department": "chemistry",
"date": datetime.datetime.now()
}
es.index(index="my_test_table", doc_type="sources", body=data, id=1234567)
当然,id
参数也可以不进行指定,系统会默认指定一个唯一的id。
2. 批量数据插入
如果要批量地进行数据的写入,当然你可以暴力地使用一个for循环实现,或者更“高级”一点在加一个多线程。
但是elasticsearch库本身内置了一个批量数据写入的函数helpers.bulk
,其用法如下:
from elasticsearch import helpers
data_list = [
{"name": "Ella"},
{"name": "Fred"}
]
action = [{
"_index": "my_test_table",
"_type": "sources",
"_source": data
} for data in data_list]
helpers.bulk(es, action)
5. es数据库数据查询
1. 数据查询基础语法
es数据库的一个核心优势就在于它能够提供灵活且高效的数据搜索功能,因此,这里,我们就来重点考察一下es数据库的数据查询方法。
es数据库基础的数据查询方法还是非常简单的,es中直接的操作命令如下:
代码语言:javascript复制GET cys_test_table/_search
{
"query":{
"term":{
"name": "Alice"
}
}
}
如果要使用python来进行数据查询其方法也差不多,其具体的实现语法如下:
代码语言:javascript复制query = {
"query":{
"match_all": {}
}
}
es.search("my_test_table", body=query, doc_type="sources")
可以看到,数据检索本身的实现是非常简单的,要想灵活地获取目标数据,其核心就在于query问题要怎么去写。
因此,下面我们重点来看一下query命令的语法。
2. query命令语法简介
1. query语法基础
es数据库中的query符合json的格式,其基本格式如下:
代码语言:javascript复制{
"query": {
"match_all": {}
}
}
可以看到,每一个query事实上都是一个字典,其中包含一个query
字段,其内容为真正的查询内容,其数据格式同样为一个字典。
上述match_all
关键词是一个最为基础的命令请求,表示返回所有的数据。
2. 单条件匹配查询
对于单一条件的搜索请求,query语法是相对比较简单的,给出一个简单的样例如下:
代码语言:javascript复制{
"query": {
"term": {
"name": "Alice"
}
}
}
上述语法就是在es表格中检索name
字段为Alice
的数据。
搜索得到的结果如下:
代码语言:javascript复制{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.6931472,
"hits": [
{
"_index": "my_test_table",
"_type": "sources",
"_id": "K5GmOXgBCPJxWUBsP_1c",
"_score": 0.6931472,
"_source": {
"name": "Alice",
"gender": "female",
"age": "24",
"department": "physics"
}
}
]
}
}
检索的关键词term
表示完全匹配,针对的是keyword
类型的关键词。
除了term
之外,其他还有match
关键词,表示部分匹配。
但是需要注意的是,它针对的必然是text
类型的属性,对于keyword
类型的数据,es表格是将其作为整体进行储存的,不会对其建立倒排索引。
3. 范围条件查询
除了直接的匹配关系之外,es还支持对范围进行搜索,检索关键词为range
。
我们给出一个简单的例子如下:
代码语言:javascript复制{
"query": {
"range":{
"date": {
"gt": "now-1d",
"lte": "now"
}
}
}
}
其中,关系词可以包括:
- gt: 大于( > > >)
- lt: 小于( < < <)
- gte: 大于等于( ≥ ≥ ≥)
- lte: 小于等于( ≤ ≤ ≤)
更为具体的可以参考链接:
- https://www.elastic.co/guide/cn/elasticsearch/guide/current/_ranges.html
4. 多条件匹配查询
同样的,对于多条件匹配查询语言,或者说组合条件查询语言,我们同样先给出一个简单的样例,然后再进行具体的展开。
给出一个样例如下:
代码语言:javascript复制{
"query": {
"bool": {
"must": [
{
"term":{"name": "Alice"}
},
{
"term": {"age": 24}
}
]
}
}
}
上述query语句表示在数据库中检索名字为Alice且年龄为24岁的人,must表示与条件,即list中的所有条件均需满足。
除了must之外,还有以下一些关键词可以用于多条件组合搜索:
- should:表示或条件,即list当中只要满足其一即可;
- must_not:list当中所有条件均不能满足,即
not any
条件;
当然,从上可以看到,es的query语句是非常灵活的,在must条件当中复合更多的条件也是可行的,写的时候注意一下语法就行了。
6. es数据库数据删除
1. es数据库中操作命令
最后,我们来考察以下如何从es数据库中删除数据。
从表中删除数据的命令同样为delete,只要指定表的域以及数据的id即可对数据进行删除。
给出一个例子如下:
代码语言:javascript复制DELETE my_test_table/sources/123456
上述命令即可从my_test_table
这张表中的sources域中删除id为123456的数据。
2. 使用python进行数据删除
现在,我们来考察一下如何使用python对es表进行数据删除。
一种比较直接的方式是和前面直接操作相同,通过数据的id直接来对数据进行删除,其实现代码如下:
代码语言:javascript复制index_name="my_test_table"
es.delete(index_name, doc_type="sources", id="123456")
不过,在更多的情况下,事实上我们是想像检索数据那样直接删除一些满足条件的数据。这时,我们可以采用delete_by_query
命令,其实现代码如下:
index_name="my_test_table"
query = {
"query":{
"term":{
"name": "Alice"
}
}
}
es.delete_by_query(index_name, query, doc_type="sources")
7. 总结
以上便是我对于es数据库使用方面的一些简单的总结,相信对于入门应该是足够了,至少就我而言,目前已经足以支持我完成工作中的一些简单问题了。
但是,如前所述,数据库本身博大精深,光是es其核心的原理设计以及其内部数据的存储模式就已经是一个很值得深入研究的点了,这里仅仅只是浅尝辄止,如果真的是这个方向的专业人员的话,还是建议后续进一步研究一下官网的文档。
8. 参考链接
- https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
- https://www.elastic.co/guide/en/elasticsearch/reference/6.0/getting-started.html
- https://www.cnblogs.com/Neeo/articles/10788573.html
- https://elasticsearch-py.readthedocs.io/en/6.8.2/api.html#elasticsearch
- https://www.elastic.co/guide/cn/elasticsearch/guide/current/combining-queries-together.html
- ES 22 - Elasticsearch中如何进行日期(数值)范围查询
- https://segmentfault.com/a/1190000010595007
- https://www.cnblogs.com/sunsky303/p/9438737.html
- https://www.jianshu.com/p/7d687c9dba4f