elasticsearch(ES)的使用

文章目录

  • 1. 安装ES
    • 1.1 安装ES
    • 1.2. 安装插件
  • 2. ElasticSearch添加密码验证
  • 3. 概念及用postman初体验
    • 3.1 基本概念:索引、文档、映射
    • 3.2 创建数据
    • 3.3 查询数据
  • 4. 常用语法
    • 4.1 match query
    • 4.2 match_phrase query
    • 4.3 term query
    • 4.4 terms query
    • 4.5 filter query
    • 4.6 range query
    • 4.7 组合查询[bool query]
    • 4.8 wildcard 通配符查询
    • 4.9 boosting query
    • 4.10 sort 排序
  • 5. python中使用es
    • 5.1 使用requests请求操作es
    • 5.2 使用 Elasticsearch 包
  • 6. 踩坑记录
    • 6.1 es中的term和match的区别
  • 参考

1. 安装ES

1.1 安装ES

安装es: 官网下载解压

  • 启动 bin/elasticsearch -d (后台启动)

  • 判断是否成功的标志 curl http://localhost:9200/?pretty
    9200是es的默认端口,可以在config/elasticsearch.yml中修改

    启动成功如下图所示:
    在这里插入图片描述

1.2. 安装插件

  • head 插件
    head插件是es的一个可视化插件,类似于workbench跟mysql的关系

    进入github head github 按照readme 文件安装,我这里选择的是以谷歌浏览器插件的方式安装,如下图
    在这里插入图片描述

  • marvel插件
    marvel插件主要是用来监控的,也可以用来当console来使用

  • postman
    用于和es交互,发送请求

2. ElasticSearch添加密码验证

1. 修改配置文件
在es包下的config目录修改es的默认配置文件elasticsearch.yml,在该文件后追加如下配置

xpack.security.enabled: true
## 加密方式
xpack.license.self_generated.type: basic
xpack.security.transport.ssl.enabled: true

2. 设置密码
重启es让配置文件生效,再到es包下bin目录执行以下命令

.\elasticsearch-setup-passwords interactive

效果如下
在这里插入图片描述
3. postman中登录
在这里插入图片描述
其他地方也是使用同样的方法登录,用户名为:elastic,密码为:123456

3. 概念及用postman初体验

3.1 基本概念:索引、文档、映射

节点 Node、集群 Cluster 和分片 Shards
ElasticSearch 是分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个实例。单个实例称为一个节点(node),一组节点构成一个集群(cluster)。分片是底层的工作单元,文档保存在分片内,分片又被分配到集群内的各个节点里,每个分片仅保存全部数据的一部分。

索引 Index、类型 Type 和文档 Document
如果我们要访问一个文档元数据应该包括囊括 index/type/id 这三种类型

对比 MySQL 数据库:

index → db
type → table
document → row

每一条数据就是一个document, 此处id可以在插入数据时指定,不指定也会自动生成

映射
映射(mapping) 是用来事先定义插入数据中字段的数据类型、字段的权重、分词器等属性,就如同在关系型数据库中创建数据表时会设置字段的类型。在 Elasticsearch 中,映射可分为动态映射和静态映射,静态映射是写入数据之前对字段的属性进行手工设置,动态映射是可直接创建索引并写入文档,文档中字段的类型是 Elasticsearch 自动识别的,不需要在创建索引的时候设置字段的类型。

参考 Elasticsearch 索引映射类型及mapping属性详解

3.2 创建数据

所有语言可以使用 RESTful API 通过端口 9200 和 Elasticsearch 进行通信。一个 Elasticsearch 请求和任何 HTTP 请求一样由若干相同的部件组成:

curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
  • VERB是 HTTP 方法,可选 : GET、 POST、 PUT、 HEAD 或者 DELETE
  • PROTOCOL 即 http 或者 https
  • HOST Elasticsearch 集群中任意节点的主机名,用 localhost 代表本地机器上的节点
  • PORT 运行 Elasticsearch HTTP 服务的端口号,默认是 9200
  • PATH API 的终端路径(例如 _count 将返回集群中文档数量)Path 可能包含多个组件,例如:_cluster/stats 和 _nodes/stats/jvm
  • QUERY_STRING 任意可选的查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读)
  • BODY 一个 JSON 格式的请求体

HTTP 命令PUT新建文档, GET 可以用来检索文档,同样的,可以使用 DELETE 命令来删除文档,以及使用 HEAD 指令来检查文档是否存在。如果想更新已存在的文档,只需再次 PUT

下面使用postman和es来交互进行数据创建和查询:

创建数据
创建员工目录,为每个员工的文档(document)建立索引,每个文档包含了相应员工的所有信息

  1. 每个文档的类型为employee
  2. employee类型归属于索引megacorp
  3. megacorp索引存储在Elasticsearch集群中
PUT /megacorp/employee/3
{"first_name" :  "Douglas","last_name" :   "Fir","age" :         35,"about":        "I like to build cabinets","interests":  [ "forestry" ]
}

在postman中操作如下
在这里插入图片描述
插入三个数据可以使用head插件查看相关信息:
在这里插入图片描述

3.3 查询数据

可以通过http get来获信息

GET /megacorp/employee/1

返回

{"_index" :   "megacorp","_type" :    "employee","_id" :      "1","_version" : 1,"found" :    true,"_source" :  {"first_name" :  "John","last_name" :   "Smith","age" :         25,"about" :       "I love to go rock climbing","interests":  [ "sports", "music" ]}
}

在这里插入图片描述
_index 索引名称
_type 类型名称
_id id(这个id可以自己指定也可以自动生成)
_version 版本号,每次改动会+1
found true表示在document存在
_source document的全部内容

轻量级搜索
查询字符串

GET /megacorp/employee/_search?q=last_name:Smith

返回

{"took": 31,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": {"value": 2,"relation": "eq"},"max_score": 0.4700036,"hits": [{"_index": "megacorp","_type": "employee","_id": "1","_score": 0.4700036,"_source": {"first_name": "John","last_name": "Smith","age": 25,"about": "I love to go rock climbing","interests": ["sports","music"]}},{"_index": "megacorp","_type": "employee","_id": "2","_score": 0.4700036,"_source": {"first_name": "Jane","last_name": "Smith","age": 32,"about": "I like to collect rock albums","interests": ["music"]}}]}
}

在这里插入图片描述
Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。我们可以这样表示之前关于“Smith”的查询

GET /megacorp/employee/_search
{"query" : {"match" : {"last_name" : "Smith"}}
}

在这里插入图片描述
过滤器
更复杂的搜索,使用过滤器(filter)来实现sql中where的效果,比如:你想要搜索一个叫Smith,且年龄大于30的员工,可以这么检索.

{"query": {"bool": {"filter": {"range": {"age": {"gt": 30}}},"must": {"match": {"last_name": "Smith"}}}}
}

在这里插入图片描述
短语搜索

GET /megacorp/employee/_search
{"query" : {"match_phrase" : {"about" : "rock climbing"}}
}

match_phrase与match的区别在于,前者会把rock climbing(搜索条件)作为一个整体,而后者会命中rock balabala climbing(后者只要命中其中一个词就算命中,比如rock climbing中命中rock就算匹配中了,就会返回结果)
在这里插入图片描述

4. 常用语法

4.1 match query

用于搜索单个字段,首先会针对查询语句进行解析(经过 analyzer),主要是对查询语句进行分词,分词后查询语句的任何一个词项被匹配,文档就会被搜到,默认情况下相当于对分词后词项进行 or 匹配操作

GET article/_search
{"query": {"match": {"title": {"query": "Elasticsearch 查询优化"}}}
}

等同于

GET article/_search
{"query": {"match": {"title":  "Elasticsearch 查询优化"}}
}

也等同于

GET article/_search
{"query": {"match": {"title": {"query": "Elasticsearch 查询优化","operator": "or"}}}
}

如果要匹配所有关键词使用and

GET article/_search
{"query": {"match": {"title": {"query": "Elasticsearch 查询优化","operator": "and"}}}
}

4.2 match_phrase query

match_phrase query 首先会把 query 内容分词,分词器可以自定义,同时文档还要满足以下两个条件才会被搜索到:

  • 分词后所有词项都要出现在该字段中(相当于 and 操作)
  • 字段中的词项顺序要一致
GET test_idx/test_tp/_search
{"query": {"match_phrase": {"desc": "what life"}}
}

4.3 term query

term 查询用来查找指定字段中包含给定单词的文档,term 查询语句不被解析,只有查询词和文档中的词精确匹配才会被搜索到,应用场景为查询人名、地名等需要精准匹配的需求

GET books/_search
{"query": {"term": {"title": "思想"}}
}

4.4 terms query

terms 查询是 term 查询的升级,可以用来查询文档中包含多个词的文档。比如,想查询 title 字段中包含关键词 “java” “python” 的文档,构造查询语句如下:

{"query": {"terms": {"title": ["java", "python"]}}
}

4.5 filter query

filter 类似于 SQL 里面的where 语句,和上面的基础查询比起来,也能实现搜索的功能,同时 filter 可以将查询缓存到内存当中,这样可以大大加大下一次的查询速度

下面实现 select document FROM products WHERE price = 20

GET /store/products/_search        // store 索引名   products 商品名
{"query":{"bool":{"query":{"match_all":{}   // 匹配所有}"filter":{"term":{ "price":20}}}}
}

4.6 range query

range query 即范围查询,用于匹配在某一范围内的数值型、日期类型或者字符串型字段的文档,比如搜索哪些书籍的价格在 50 到 100之间、哪些书籍的出版时间在 2015 年到 2019 年之间。使用 range 查询只能查询一个字段,不能作用在多个字段上

range 查询支持的参数有以下几种:

  • gt 大于
  • gte 大于等于
  • lt 小于
  • lte 小于等于
// 查询价格大于 50,小于等于 70 的书籍
GET bookes/_search
{"query": {"range": {"price": {"gt": 50,"lte": 70}}}
}

4.7 组合查询[bool query]

bool query(组合查询)是把任意多个简单查询组合在一起,使用 must、should、must_not、filter 选项来表示简单查询之间的逻辑,每个选项都可以出现 0 次到多次。

bool query 主要通过下列 4 个选项来构建用户想要的布尔查询,每个选项的含义如下:

  • must 文档必须匹配 must 选项下的查询条件,相当于逻辑运算的 AND,且参与文档相关度的评分
  • should 文档可以匹配 should 选项下的查询条件也可以不匹配,相当于逻辑运算的 OR,且参与文档相关度的评分
  • must_not 与 must 相反,文档 必须不 匹配这些条件才能被包含进来
  • filter 和 mysql 中 where 语句功能一样,对查询结果进行限制
GET books/_search
{"query": {"bool": {"filter": {"term": {"status": 1}},"must_not": {"range": {"price": {"gte": 70}}},"must": {"match": {"title": "java"}},"should": [{"match": {"description": "虚拟机"}}],"minimum_should_match": 1}}
}

4.8 wildcard 通配符查询

wildcard 查询:允许使用通配符 * 来进行查询

  • * 匹配任意一个或多个字符
  • ? 匹配任意一个字符
GET /library/books/_search
{“query”:{"wildcard":{"preview":"rab*"}}
}

4.9 boosting query

boosting 查询用于需要对两个查询的评分进行调整的场景,boosting 查询会把两个查询封装在一起并降低其中一个查询的评分。
boosting 查询包括 positive、negative 和 negative_boost 三个部分,positive 中的查询评分保持不变,negative 中的查询会降低文档评分,negative_boost 指明 negative 中降低的权值。

// 对 2015 年之前出版的书降低评分GET books/_search
{"query": {"boosting": {"positive": {"match": {"title": "python"}},"negative": {"range": {"publish_time": {"lte": "2015-01-01"}}},"negative_boost": 0.2}}
}

boosting 查询中指定了抑制因子为 0.2,publish_time 的值在 2015-01-01 之后的文档得分不变,publish_time 的值在 2015-01-01 之前的文档得分为原得分的 0.2 倍。

4.10 sort 排序

使用 price、date 和 _score 进行查询,并且匹配的结果首先按照价格排序,然后按照日期排序,最后按照相关性排序

GET books/_search
{"query": {"bool": {"must": {"match": { "content": "java" }},"filter": {"term": { "user_id": 4868438 }}}},"sort": [{"price": {"order": "desc"}}, {"date": {"order": "desc"}}, {"_score": {"order": "desc"}}]
}

排序条件的顺序是很重要的。结果首先按第一个条件排序,仅当结果集的第一个 sort 值完全相同时才会按照第二个条件进行排序,以此类推

5. python中使用es

5.1 使用requests请求操作es

如下图,es中已经存入以下数据,接下来进行增删查改操作
在这里插入图片描述
程序如下

import json
import requests
import os
import base64
import loggingLOG_FORMAT = "%(asctime)s  %(levelname)s  %(message)s"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)def search_es_match(host="localhost", port="9200", index="megacorp", type="employee", id="", operate="search", search_body=dict()):'''host/port: ip和端口号index: 索引名称type: es中存储数据的类型,可以为空字符串id: es存储的数据的id, 如果需要删除或者修改该条数据,必须指定idoperate: 进行何种操作: 插入/修改insert, 查询search, 删除delete'''op_map = {"search":"_search", "insert":"", "delete":""}if operate in op_map:op = op_map.get(operate)else:logging.warn("没有该操作类型: %s"%operate)return -1search_url = os.path.join(f"http://{host}:{port}", index, type, id, op )# 有密码时候带上用户及密码# auth = str(base64.b64encode(f'{self.username}:{self.password}'.encode('utf-8')), 'utf-8')# 请求头中带有Authorizationheaders = {"Content-Type": "application/json",# 'Authorization': f'Basic {auth}'}data = json.dumps(search_body)requests.DEFAULT_RETRIES = 5  # 增加重试连接次数s = requests.session()s.keep_alive = False  # 关闭多余连接if operate == "delete":r = requests.delete(search_url, headers=headers)else:r = requests.post(search_url, data=data, headers=headers)return r.json()if __name__ == "__main__":data = {"query":{"bool":{"filter":{"term":{"last_name":"smith"}},"must":{"range":{"age":{"gt":25}}},"should":{"match":{"about": "like to"}}   }   }}data2 = {"first_name": "Li","last_name": "Bai","age":72,"about": "chuang qian ming yue guang"}data3 = {"first_name": "Li","last_name": "Bai","age":72,"about": "chuang qian ming yue guang, yi shi di shang shuang"}# 插入新数据ret1 = search_es_match(id="110", operate="insert", search_body=data2)print(ret1)# 修改数据ret2 = search_es_match(id="110", operate="insert", search_body=data3)print(ret2)# 删除数据ret3 = search_es_match(id="110", operate="delete")print(ret3)# 查询数据ret4 = search_es_match(operate="search", search_body=data)print(ret4)

插入数据
ret1 结果

{'_index': 'megacorp', '_type': 'employee', '_id': '110', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 15, '_primary_term': 5}

在这里插入图片描述
修改数据结果
ret2 结果

{'_index': 'megacorp', '_type': 'employee', '_id': '110', '_version': 2, 'result': 'updated', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 16, '_primary_term': 5}

在这里插入图片描述
修改内容时,其他不修改的内容也需写入body中,否则默认会赋空值

删除数据结果
ret3 结果

{'_index': 'megacorp', '_type': 'employee', '_id': '110', '_version': 3, 'result': 'deleted', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 17, '_primary_term': 5}

在这里插入图片描述
查询数据

{'took': 121, 
'timed_out': False, 
'_shards': {'total': 1, 'successful': 1, 'skipped': 0, 'failed': 0}, 
'hits': {'total': {'value': 1, 'relation': 'eq'}, 'max_score': 2.257855, 'hits': [{'_index': 'megacorp', '_type': 'employee', '_id': '2', '_score': 2.257855, '_source': {'first_name': 'Jane', 'last_name': 'Smith', 'age': 32, 'about': 'I like to collect rock albums', 'interests': ['music']}}]}}

5.2 使用 Elasticsearch 包

参考 python 操作 ElasticSearch 入门
python操作ES数据库

6. 踩坑记录

6.1 es中的term和match的区别

现在es中存储了如下数据
在这里插入图片描述
现在用filter方法来查询 last_name=Smith 的数据,如下图,却未查询到相关的数据
在这里插入图片描述
我们再把 term 换成 match 方法,可以发现能够查询到两个结果
在这里插入图片描述

原因
term是代表完全匹配,也就是精确查询,搜索前不会再对搜索词进行分词拆解,但是Smith这个词在进行存储的时候,进行了分词处理,这里使用的是默认的分词处理器进行了分词处理,使得存入的时候将Smith 存成了 smith, 如下图所示,我们用_ananlyze方法查看存入形式:
在这里插入图片描述
因此我们在用 term 方法查询时,应该查询smith,如下图所示,查询到2个结果
在这里插入图片描述
所以,在默认分词方式下,使用term来精确查询需要全部用小写字母来查询

参考

  • 官方文档
  • 知乎-Elasticsearch【快速入门】
  • 简书-Elasticsearch入门语法
  • Elasticsearch 基础教程-程序员笔记
  • Elasticsearch添加密码验证
  • es中的term和match的区别


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部