数据库-ElasticSearch入门(索引、文档、查询)

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 数据库-ElasticSearch入门(索引、文档、查询)



前面文章,安装了ES,请再安装chrome插件elasticsearch-head。由于需要发送http的请求,可以安装postman,当然,你用其他命令行工具也可以,另外,如果不了解HTTP协议、RestFul,Json格式可以自行补充一下。

ES启动与可视化

双击elasticsearch.bat即可,之后会检查环境,加载模块,打开端口等

启动图

注意安装好jdk(自带jdk,自己装的话推荐1.8+),9300是内部组件通信端口,9200是访问端口。

可视化

打开浏览器插件可以看到信息,跟着博主下面操作的话可以时常看看可视化插件,我就不再截图了。

索引

类似关系型数据库中的“数据库”这一概念

倒排索引

正排(正向)索引:根据id去寻找内容,例如Mysql

正排索引示例

id words
1 hi, l am lady killer 9
2 hello, i like young lady

我们易于根据id去查询内容,但当查询lady是否存在时,却抛弃了索引,全表查询,即正排索引不利于全文检索,尤其是模糊查询时(Lady,LADY这种非完全匹配)。

倒排索引就是来解决这个问题的,通过分词,权重等来快速检索

倒排索引

words id
lady 1,2
killer 1

后序就不再画了,通过这种方式更加快速全文搜索。

创建

http://ip:9200/index_name,注意使用幂等PUT,POST会显示错误如下。

使用POST

使用PUT

使用PUT创建索引

创建后结果如下:

结果

查询

单个索引

http://ip:9200/index_name,使用GET方法

获取索引

所有索引

http://ip:9200/_cat/indices?v,使用GET方法,其中,参数v是为了显示更详细

创建索引killer后,可以看到如下结果

所有索引

删除

和创建时的url一致,只需要使用DELETE方法删除即可。

删除索引killer

文档

类似关系型数据库中的表数据

创建

http://ip:9200/index_name/_doc/[_id],使用方法POST需要有请求体,JSON格式。

创建文档

可以看到,生成了一个随机的_id,即同样的请求,返回不一致,由于PUT是幂等的,所以也就只能用POST。当指定_id时,可以使用POST。

指定_id创建文档

查询

主键查询

和创建时的地址一致,需要指定_id,方法改为GET即可

查询单个数据

搜索所有文档

http://ip:9200/index_name/_search,方法仍然使用GET

获取索引的所有文档

条件查询

http://ip:9200/index_name/_search?q=key:value,方法使用GET

单条件查询

请求体方式:不在url中使用参数,而是请求体,这种方式更常见,更安全。

请求体查询

分页查询

在上面的基础上,添加from和size,代表从哪条数据开始查询和每页显示的条数

from=(pagenum-1)*size,查询第一页的数据,就是(1-1)*2,即从第0条数据开始查,显示2条

查询之前,我添加了两条数据

{
    "name":"leilei",
    "type":"friend",
    "age":20
}
{
    "name":"jiajia",
    "type":"friend",
    "age":20
}

条件是"type":"friend",结果如下

结果如下

排序

在查询的基础上,添加sort字段,里面再添加要排序的字段,选择升序还是降序可以再嵌套order

排序

多条件查询

稍微复杂一些,bool里面嵌套must或should,类似and或or,,must not 类似not,看下面的请求体

{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "age":18
                    }
                },
                {
                    "match":{
                        "type":"girlfriend"
                    }
                }
            ]
        }
    }
}

这样两个match必须全部匹配到即可。类似京东选择游戏笔记本,又选择处理器是i7。

多条件查询must

使用should匹配girlfriend和20时,就能找到多个。

多条件查询should

范围查询

使用filter,gt表示大于,lt表示小于。放到bool里面,和must/must not/should并列。

"filter":{
                "range":{
                    "age":{
                        "lt":19
                    }
                }
            }

age>19的结果

完全匹配

前面使用的match是全文匹配,也就是进行了分词,不完全一致时也会匹配到

自带的分词器对于拼音的分词不太好,加了两条中文的

查询小贝结果如下:

小贝查询到宝贝、贝贝

这就类似于你在京东查询一个商品,可能没有一样的,但是并不是显示没有,而是显示类似的

使用match_phrase可以进行完全匹配查询

完全匹配小贝没有结果

高亮查询

添加highlight

高亮部分添加了em标签

聚合查询

使用aggs,表示聚合操作,嵌套分组terms,添加分组字段

聚合查询

可以看到19 20 18岁的doc数量

映射

将字段映射为关键字或文本类型,关键字不可拆分,设置index为false时不可拆分。

添加索引killer,给killer添加映射,http:///ip:9200/index_name/_mapping,方法使用PUT

{
    "properties":{
        "name":{
            "type":"keyword",
            "index":true
        },
        "hobby":{
            "type":"text",
            "index":true
        }
    }
}

添加映射

名字是关键字,不可拆分,爱好是文本,可以拆分。

添加两个文档

{
    "name":"弗兰克",
    "hobby":"枪杀"
}
{
    "name":"弗兰克林",
    "hobby":"捧杀"
}

按名字查询

按爱好查询

可以看到名字作为关键字,必须一样才能查到,爱好却能查到类似的

修改

全量修改

http://ip:9200/index_name/_doc/_id,使用PUT方法,添加请求体。

全量修改

可以看到上面数据没有全部改动,大部分情况下还是部分修改的。

局部修改

http://ip:9200/index_name/_update/_id,方法为POST,请求体使用doc字段嵌套修改内容,见下图。

部分修改

删除

http://ip:9200/index_name/_doc/_id,方法使用DELETE

删除文档

Python API

又支持异步的版本和不支持异步的,这里就使用简单的不支持异步的

安装与导入

pip install elasticsearch==7.10
from elasticsearch import Elasticsearch

包内容

项目结构

使用单元测试对API进行简单测试。后续仅展示esclient里面的函数即test_函数

初始化

def __init__(self, host="127.0.0.1", port: int = 9200):
        self._client = Elasticsearch(host=host, port=port)

参数

host: es的ip

port: es的端口

测试代码

es = Elasticsearch()

索引

创建

def index_create(self, index_name: str, map=None):
        if map is None:
            map = {}
        res = self._client.index(index=index_name, body=map)
        return res

参数

index:索引名

body:请求体

测试代码

def test_index_create(self):
        res = es.index_create("lady1")
        print(res)
        res = es.index_create("heros", map={
            "mapping": {
                "doc": {
                    "properties": {
                        "name": {
                            "type": "text",
                            "index": True
                        },
                        "age": {
                            "type": "keyword",
                            "index": True
                        },
                        "role": {
                            "type": "keyword",
                            "index": True
                        }
                    }
                }
            }
        })
        print(res)

结果

使用wireshark抓包

可以看到是一个POST包,使用的是json格式,body是空的

这个是有body的,但是映射貌似也不对,没有向_mapping发送,后面我们自己发送一个PUT数据包

创建映射

测试代码

def test_mapping(self):
        import requests
        import json
        url_put = "http://127.0.0.1:9200/heros/_mapping"
        headers_put = {
            'Content-Type': "application/json"
        }
        param ={
            "properties": {
                "name": {
                    "type": "text",
                    "index": True
                },
                "role": {
                    "type": "keyword",
                    "index": True
                }
            }
        }
        payload = json.dumps(param)
        response_put = requests.put(url_put, data=payload, headers=headers_put)
        print(response_put.text)

测试结果

之后就不再展示Wireshark抓包结果了

删除索引

def index_delete(self, index_name: str):
        res = self._client.indices.delete(index=index_name)
        return res

参数

index_name:索引的名字

测试代码

def test_index_delete(self):
        res = es.index_delete(index_name="lady1")
        print(res)

结果

查询

单个索引

def index_get(self, index_name: str):
        res = self._client.indices.get(index=index_name)
        return res

参数

index_name:索引的名字

测试代码

def test_index_get(self):
        res = es.index_get("heros")
        print(res)

结果

文档

创建

def doc_create(self, index_name, body, id_):
        res = self._client.create(index=index_name, body=body, id=id_)
        return res

参数

index_name:索引的名字

body:请求体

id_:文档的id

测试代码

def test_doc_create(self):
        zhaoyun = {
            "name": "赵云",
            "age": 25,
            "role": "打野"
        }
        yunzhongjun = {
            "name": "云中君",
            "age": 25,
            "role": "打野"
        }
        yao = {
            "name": "瑶",
            "age": 16,
            "role": "辅助"
        }
        sunshangxiang = {
            "name": "孙尚香",
            "age": 18,
            "role": "射手"
        }
        liubei = {
            "name": "刘备",
            "age": 30,
            "role": "打野"
        }
        heros = [zhaoyun, yunzhongjun, yao, sunshangxiang, liubei]
        init_id = 1000
        for h in heros:
            res = es.doc_create("heros", h, str(init_id))
            init_id += 1
            print(res)

结果

删除

def doc_delete(self, index_name, doc_id):
        res = self._client.delete(index=index_name, id=doc_id)
        return res

参数

index_name:索引的名字

doc_id:文档的id

一共就这几个数据,我就不删除了

修改

def doc_update(self, index_name, doc_id, doc):
        res = self._client.update(index=index_name, id=doc_id, body=doc)
        return res

参数

index_name:索引的名字

doc_id:文档的id

doc:文档

测试代码

def test_doc_update(self):
        sun = {
            "doc": {
                "age": 21
            }
        }
        res = es.doc_update("heros", "1002", sun)
        print(res["result"])

结果

查询

查询所有

def doc_get__all(self, index_name):
        res = self._client.search(index=index_name)
        return res['hits']['hits']

参数

index_name:索引的名字

这里仅返回hit到的json对象列表

测试代码

def test_doc_get_all(self):
        res = es.doc_get__all("heros")
        for hit in res:
            print(hit["_source"])

结果

根据id查询

def doc_get_id(self, index_name, id_):
        res = self._client.get(index=index_name, id=id_)
        return res["_source"]

参数

index_name:索引的名字

id_:文档的id

测试代码

def test_doc_get_id(self):
        res = es.doc_get_id("heros", "1002")
        print(res)

结果

根据条件查询

def doc_get_condition(self, index_name, con):
        res = self._client.search(index=index_name, body=con)
        return res['hits']['hits']

参数

index_name:索引的名字

con:查询的请求体,即条件

单个条件

测试代码

def test_doc_get_con_1(self):
        name = {
            "name": "小云"
        }
        con = {
            "query": {
            }
        }
        con["query"]["match"] = name
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["_source"])

结果

因为name在前面设置映射时,设置为了text,所以即使不完全匹配也会有类似的结果。

分页查询

测试代码

def test_doc_get_page(self):
        page_num = 2
        size = 3
        con = {
            "from": (page_num - 1) * size,
            "size": size
        }
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["_source"])

结果

对结果排序

测试代码

def test_doc_get_sort(self):
        page_num = 1
        size = 3
        field = "age"
        order = "desc"
        con = {
            "from": (page_num - 1) * size,
            "size": size,
            "sort": {
                field: {
                    "order": order
                }
            }
        }
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["_source"])

结果

多个条件查询

测试代码

def test_doc_get_con_more(self):
        eighteen_match = {
            "match": {
                "age": "18"
            }
        }
        daye_match = {
            "match": {
                "role": "打野"
            }
        }
        con = {
            "query": {
                "bool": {
                    "must_not": []
                }
            }
        }
        con["query"]["bool"]["must_not"].append(eighteen_match)
        con["query"]["bool"]["must_not"].append(daye_match)
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["_source"])

结果

范围查询

测试代码

def test_doc_get_scope(self):
        filter = {
            "range": {
                "age": {
                    "gt": 19
                }
            }
        }
        con = {
            "query": {
                "bool": {
                    "filter": filter
                }
            }
        }
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["_source"])

结果

完全匹配

测试代码

def test_doc_get_phrase(self):
        name = {
            "name": "赵云"
        }
        con = {
            "query": {
            }
        }
        con["query"]["match_phrase"] = name
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["_source"])

结果

高亮查询

测试代码

def test_doc_get_highlight(self):
        name = {
            "name": "云"
        }
        con = {
            "query": {
            },
            "highlight": {
                "fields": {
                    "name": {}
                }
            }
        }
        con["query"]["match"] = name
        res = es.doc_get_condition("heros", con)
        for hit in res:
            print(hit["highlight"])

结果

聚合查询

def doc_get__agg(self, index_name, con):
        res = self._client.search(index=index_name, body=con)
        return res['aggregations']

参数

index: 索引的名字

body:请求体,即聚合的字段

测试代码

def test_doc_get_aggs(self):
        con = {
            "aggs": {
                "role_groups": {
                    "terms": {
                        "field": "role"
                    }
                }
            },
        }
        res = es.doc_get__agg("heros", con)
        for cnt in res["role_groups"]["buckets"]:
            print(cnt["key"], " ", cnt["doc_count"])

结果

参考

Postman

网络-http协议学习笔记(消息结构、请求方法、状态码等)_lady_killer9的博客-CSDN博客

Quick start | Elasticsearch Guide [7.15] | Elastic

Elasticsearch Python Client [7.16] | Elastic

Python Elasticsearch Client — Elasticsearch 8.0.0 documentation

Elasticsearch: 权威指南 | Elastic


更多ELK相关内容:数据库-ElasticSearch学习笔记_lady_killer9的博客-CSDN博客

喜欢本文的请动动小手点个赞,收藏一下,有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!

如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

 

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
23天前
|
SQL 数据可视化 关系型数据库
轻松入门MySQL:深入探究MySQL的ER模型,数据库设计的利器与挑战(22)
轻松入门MySQL:深入探究MySQL的ER模型,数据库设计的利器与挑战(22)
105 0
|
23天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
|
23天前
|
关系型数据库 MySQL 数据库
轻松入门MySQL:精准查询,巧用WHERE与HAVING,数据库查询如虎添翼(7)
轻松入门MySQL:精准查询,巧用WHERE与HAVING,数据库查询如虎添翼(7)
|
19天前
|
存储 关系型数据库 MySQL
MySQL基础入门:数据库操作全攻略
MySQL基础入门:数据库操作全攻略
48 0
|
2天前
|
安全 API 数据安全/隐私保护
Elasticsearch 通过索引阻塞实现数据保护深入解析
Elasticsearch 通过索引阻塞实现数据保护深入解析
|
3天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.2数据库编程——了解SQL语言,编写基本查询语句
Java从入门到精通:2.3.2数据库编程——了解SQL语言,编写基本查询语句
|
3天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
3天前
|
存储 网络协议 关系型数据库
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
Python从入门到精通:2.3.2数据库操作与网络编程——学习socket编程,实现简单的TCP/UDP通信
|
8天前
|
SQL 关系型数据库 MySQL
mysql 数据库查询 查询字段用逗号隔开 关联另一个表并显示
mysql 数据库查询 查询字段用逗号隔开 关联另一个表并显示
18 2
|
10天前
|
SQL 存储 Oracle
关系型数据库查询数据的语句
本文介绍了关系型数据库中的基本SQL查询语句,包括选择所有或特定列、带条件查询、排序、分组、过滤分组、表连接、限制记录数及子查询。SQL还支持窗口函数、存储过程等高级功能,是高效管理数据库的关键。建议深入学习SQL及相应数据库系统文档。
9 2