Elasticsearch
1-Elasticsearch相关概念
# 特点:
1.具有HTTP Web接口和JSON文档
2.RESTful API 通过端口 9200 和 Elasticsearch 进行通信
3.Elasticsearch是用Java开发的--但是客户端在python中能使用
4.Elasticsearch是分布式的---数据可以分片
5、Elasticsearch 是一个实时的分布式搜索分析引擎,
1.全文检索、2.结构化搜索、3.分析
6.Elasticsearch 有2.x、5.x、6.x 三个大版本,我们在黑马头条中使用5.6版本。
# 终端发送网络请求命令
curl -X 请求方式的大写(GET POST) ip地址:端口号/路径 -H "请求头内容" -d "请求体内容"
curl -X GET 127.0.0.1:9200/_cluster/health?pretty
# get请求简写形式
curl 127.0.0.1:9200/_cluster/health?pretty
# 我是中&国人
# 标准分词: 我 是 中 国 人
# IK中文分词:我 是 中国 中国人 国人
2-Elasticsearch搜索的原理
# 终端命令发送请求的格式:
curl -X 请求方法 ip和端口 -H "application/json" -d '发送给ES的json格式数据'
# get请求的缩写形式
curl ip和端口 -H "application/json" -d '发送给ES的json格式数据'
# 1.倒排索引
# 2.分析,标准处理
# 3.相关性排序
curl语法格式:
curl -X 请求方式 请求地址 -H "Content-Type: application/json" -d '
{
"key" : "value"
}
'
Term Doc_1 Doc_2
-------------------------
brown | X | X
quick | X |
------------------------
Total | 2 | 1
越罕见---相关性越高
brown daslkdslkalksalkdlkaslda -- 占比少,相关性低
brown web --占比高 相关性高
3-ES概念与集群
存储数据到 Elasticsearch 的行为叫做 索引 (indexing)
# 对比学习
Relational DB -> Databases 数据库 -> Tables 表 -> Rows 行 -> Columns 列
Elasticsearch -> Indices 索引库 -> Types 类型 -> Documents 文档 -> Fields 字段/属性
# Elasticsearch 集群(cluster)
curl命令:
在终端发送请求的命令
格式:
curl -X 请求方式 ip地址+端口号 -H "请求携带内容" -d '发送的数据'
举例:
curl -X PUT 127.0.0.1:9200/articles -H 'Content-Type: application/json' -d '
{
"settings" : {
"index": {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
}
'
# 查看集群健康状态
curl -X GET 127.0.0.1:9200/_cluster/health?pretty
curl -X 请求方式 ip:端口 -h "请求头信息" -d '请求要发生的数据'
echo $? # 查询上一条指令是否执行成功,0代表成功,其余就是失败
4-IK中文分析器
"我是&中国人"
默认分词:
IK中文分析器:
发送请求语法:_analyze 固定接口关键字
curl -X GET 127.0.0.1:9200/_analyze?pretty -d '
{
"analyzer": "ik_max_word",
"text": "我是&中国人"
}'
# "analyzer": "ik_max_word" 选用ik中文分词器
5-索引
索引 ---> 数据库
类型 ---> 表
查看索引:curl 127.0.0.1:9200/_cat/indices
创建索引:在Elasticsearch 5.x版本中,
1.设置分片
2.设置索引的类型字段需要分两次设置完成
// 文章索引 ---设置三个分片,每个分片一个复制集
curl -X PUT 127.0.0.1:9200/articles -H 'Content-Type: application/json' -d'
{
"settings" : {
"index": {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
}
'
6-类型和映射
类型和映射--理解成mysql数据库中的表里面字段需要设置什么类型。
字符串: text (在elaticsearch 2.x版本中,为string类型)
整数 : byte, short, integer, long
浮点数: float, double
布尔型: boolean
日期: date
# _all
字段是把所有其它字段中的值,以空格为分隔符组成一个大字符串,然后被分析和索引
方便后续对title和content进行全文检索
# include_in_all
参数用于控制 _all 查询时需要包含的字段。默认为 true。
# "analyzer": "ik_max_word", 指明分析器为:IK中文分析器
存储建立倒排索引的时候,分析器的类型
查询检索的时候,分析器的类型
# boost 可以提升查询时计算相关性分数的权重
"title": {
"type": "text",
"analyzer": "ik_max_word",
"include_in_all": "true",
"boost": 2
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"include_in_all": "true"
},
7-类型和映射–修改方式
# 查看类型映射 ---理解成查看数据库表[show tables]
curl 127.0.0.1:9200/articles/_mapping/article?pretty
# 关于--映射修改
1.可以为类型增加新的字段映射
2.但是不能修改已有字段的类型映射,原因在于elasticsearch已按照原有字段映射生成了反向索引数据
# 注意:非要修改---步骤
1.需要从新建立索引(数据库)
curl -X PUT 127.0.0.1:9200/新的索引库名称/_mapping/新的类型名称
2.重新索引数据--将原有库的数据,导入到新的库中
curl -X POST 127.0.0.1:9200/_reindex
3.为索引起别名--新建的索引具有原索引的名字(方便用户使用)
curl -X PUT 127.0.0.1:9200/原名称/_alias/别名
# 查询文章数据
select a.article_id as article_id,a.user_id as user_id, a.title as title, a.status as status, a.create_time as create_time, b.content as content
from news_article_basic as a inner join news_article_content as b
on a.article_id=b.article_id
select 要查询的字段名称: article_id user_id title status create_time content
from 从那张表查询 联合查询
on 通过那个字段将两张表联合 article_id
control + c 停止进程
control + z 挂起进程
lsof -i:5000
ps aux | grep xx
8-文档的增删改查
# _index: 文档在哪存放
# _type: 文档表示的对象类别
# _id: 文档唯一标识
# 1.新增文档数据--PUT请求
curl -X PUT 127.0.0.1:9200/索引名称/类型名称/id[可选]
curl -X PUT 127.0.0.1:9200/articles/article/150000 -H 'Content-Type:application/json' -d '
{
"article_id": 150000,
"user_id": 1,
"title": "python是世界上最好的语言",
"content": "确实如此",
"status": 2,
"create_time": "2019-04-03"
}'
# 2.查询文档数据--GET请求
curl 127.0.0.1:9200/索引名称/类型名称/id值
# 3.判断文档是否存在--HEAD请求
curl -i -X HEAD 127.0.0.1:9200/索引名称/类型名称/id值
-i 参数可以显示 http response 的头信息
#4.更新文档 --- 先删除原有数据,再写入新的数据,并不是局部更新
# 5.删除文档--DELETE请求
curl -X DELETE 127.0.0.1:9200/索引名称/类型名称/id值
09-Logstash导入数据
- ###需求:从MySQL导入文章数据到Elasticsearch
# 1.创建配置文件logstash_mysql.conf
# 2、解压缩java驱动包
tar xzvf mysql-connector-java-8.0.13.tar.gz
# 3、执行输入导入命令
sudo /usr/share/logstash/bin/logstash -f ./logstash_mysql.conf
# 读取的源
input{
jdbc {
# java读取数据库的驱动
jdbc_driver_library => "/home/python/mysql-connector-java-8.0.13/mysql-connector-java-8.0.13.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
# 数据库连接信息
jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/toutiao?tinyInt1isBit=false"
jdbc_user => "root"
jdbc_password => "mysql"
# 是否分页读取
jdbc_paging_enabled => "true"
# 每一页多少条数据
jdbc_page_size => "1000"
# 时间类型-时区
jdbc_default_timezone =>"Asia/Shanghai"
# 重要***:需要读取什么数据,对应的sql语句,后续跟进需求而定
statement => "select a.article_id as article_id,a.user_id as user_id, a.title as title, a.status as status, a.create_time as create_time, b.content as content from news_article_basic as a inner join news_article_content as b on a.article_id=b.article_id"
use_column_value => "true"
# 将那个字段作为ES的主键
tracking_column => "article_id"
clean_run => true
}
}
# 写入的源
output{
elasticsearch {
# ES 地址
hosts => "127.0.0.1:9200"
# 索引库名称
index => "articles"
# 文档唯一标识--主键
document_id => "%{article_id}"
# 类型表名称
document_type => "article"
}
stdout {
# 终端输出导入的结果
codec => json_lines
}
}
# 注意: 由于数据太多,时间太长
control + c 停止程序运行
control + z 程序挂起
10-ES基本查询
# 1.根据文档ID
curl -X GET 127.0.0.1:9200/索引库名称/类型名称/id值
# 2.查询所有 关键字:_search 需要显示的字段:_source 指明
curl -X GET 127.0.0.1:9200/articles/article/_search?_source=title,user_id
# 3.分页 from 起始值 size 每页数量
curl -X GET 127.0.0.1:9200/articles/article/_search?_source=title,user_id\&size=3\&from=10
# 4.全文检索: q=搜索的字段名称:搜索的关键字
# 举例:搜索文章的内容包含python web的 文章标题和文章id
_search?q=content:python%20web\&_source=title,article_id\&pretty
# 注意: %20代表空格
# 举例:搜索全部内容包含python web的 文章标题和文章id
_search?q=_all:python%20web\&_source=title,article_id\&pretty
11-ES高级查询
# _search:表示查询数据
curl -X GET 127.0.0.1:9200/索引库名称/类型名称/_search?pretty -d '查询条件'
# 全文检索: match
curl -X GET 127.0.0.1:9200/articles/article/_search?pretty -d'
{
# 偏移条数
"from": 0,
# 每页5条数据
"size": 5,
# 返回结果只需要:article_id和title字段
"_source": ["article_id","title"],
"query" : {
# 全文检索
"match" : {
# 从_all中查询关键词 :python web 编程
"_all" : "python web 编程"
}
}
}'
# 短语搜索 match_phrase
"query" : {
"match_phrase" : {
"_all" : "python web"
}
}
# 精确查找 term
"query" : {
"term" : {
"user_id" : 1
}
}
# 范围查找 range
"query" : {
"range" : {
# 条件 3 <= article_id <= 5
"article_id": {
"gte": 3,
"lte": 5
}
}
}
# 高亮搜索 highlight
eg: 结果值中title字段显示高亮
"highlight":{
"fields": {
"title": {}
}
}
# 组合查询
must:文档 必须 匹配这些条件才能被包含进来
must_not:文档 必须不 匹配这些条件才能被包含进来。
should:将增加相关性_score 查询
filter: 过滤查询
# 排序
"sort": [
{ "create_time": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
# boost 提升权重,优化排序
"query" : {
"match" : {
"title" : {
"query": "python web",
"boost": 4
}
}
}
12-ES在python客户端使用
# 1.安装
pip install elasticsearch
# 2.导入ES5
from elasticsearch5 import Elasticsearch
# 3.# 创建ES客户端
es = Elasticsearch(
ES,
# 启动前嗅探es集群服务器---顺藤摸瓜
sniff_on_start=True,
# es集群服务器结点连接异常时是否刷新es结点信息
sniff_on_connection_fail=True,
# 每60秒刷新结点信息
sniffer_timeout=60
)
# 4.全文检索
参数1:索引库名称 参数2:类型库名称 参数3:查询的具体数据--dict
ret = es.search(index='articles', doc_type='article', body=query)
# 启动前嗅探es集群服务器
指定集群中的某一个节点(不一定是主节点),然后会加载集群中的其他节点,这样只要程序不停即使此节点宕机仍然可以连接到其他节点。
13-头条全文检索实现
# 查询的内容
query = {
'from': (page-1)*per_page,
'size': per_page,
'_source': False,
'query': {
'bool': {
'must': [
{'match': {'_all': q}}
],
'filter': [
{'term': {'status': 2}}
]
}
}
}
# 使用es对象的search方法获取-检索结果
ret = current_app.es.search(index='articles', doc_type='article', body=query)
# 检索结果总条数
total_count = ret['hits']['total']
14-联想提示—拼写纠错
curl 127.0.0.1:9200/articles/article/_search?pretty -d '
{
"from": 0,
"size": 10,
"_source": false,
"suggest": {
# 用户输入的—错误词汇
"text": "phtyon web",
# 自定义:结果保存的字符串
"word-phrase": {
"phrase": {
"field": "_all",
"size": 1
}
}
}
}
'
# 结果:es可以提供根据索引库数据得出的正确拼写python web
15-联想提示—自动补全
# 1.再建立一个自动补全的索引库--completions
curl -X PUT 127.0.0.1:9200/completions -H 'Content-Type: application/json' -d'
{
"settings" : {
"index": {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
}
'
# 2.在自动补全的索引库中创建类型--words
curl -X PUT 127.0.0.1:9200/completions/_mapping/words -H 'Content-Type: application/json' -d'
{
"words": {
"properties": {
# 自动补全关键字-suggest
"suggest": {
# 类型--自动补全completion类型
"type": "completion",
"analyzer": "ik_max_word"
}
}
}
}
'
# 3.创建logstash_mysql_completion.conf文件
input{
jdbc {
jdbc_driver_library => "/home/python/mysql-connector-java-8.0.13/mysql-connector-java-8.0.13.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/toutiao?tinyInt1isBit=false"
jdbc_user => "root"
jdbc_password => "mysql"
jdbc_paging_enabled => "true"
jdbc_page_size => "1000"
jdbc_default_timezone =>"Asia/Shanghai"
statement => "select title as suggest from news_article_basic"
clean_run => true
}
}
output{
elasticsearch {
hosts => "127.0.0.1:9200"
index => "completions"
document_type => "words"
}
}
# 4.执行命令logstash导入初始数据
sudo /usr/share/logstash/bin/logstash -f ./logstash_mysql_completion.conf
# 5.自动补全建议查询
curl 127.0.0.1:9200/completions/words/_search?pretty -d '
{
"suggest": {
# 自定义字段:搜索补全的结果保存在该字段中
"title-suggest" : {
# 用户输入的补全词汇
"prefix" : "pyth",
"completion" : {
"field" : "suggest"
}
}
}
}
'
16-头条suggest查询实现
pthyon web ----> 纠错处理 python web
pyth ---> 自动补全 python
pa ---> 自动补全 path
# 1.先尝试自动补全建议查询
query = {
'from': 0,
'size': 10,
'_source': False,
'suggest': {
# 结果保存的字符串 自定义的字符串,可以修改
'word-completion': {
# 获取前端输入的,需要补全的字符串
'prefix': "需要补全的关键字",
'completion': {
'field': 'suggest'
}
}
}
}
#2. 使用ES对象 search函数获取补全结果
ret = current_app.es.search(index='completions', body=query)
#3. 提取补全结果中的信息
options = ret['suggest']['word-completion'][0]['options']
17-单元测试
单元测试---对单独的代码块(例如函数)分别进行测试,以保证它们的正确性
说白了就是:编写单元测试代码`测试`逻辑代码
# 步骤:
1.定义一个类,继承自unittest.TestCase
2.准备工作
#初始化方法,方法名为固定写法
def setUp(self):
pass
#测试代码执行完后执行,方法名为固定写法
def tearDown(self):
pass
3. 测试方法
# 注意: 必须 test_ 开头
def test_app_exists(self):
pass
4.编写单元测试案例
18-使用gunicorn 运行flask代码
###gunicorn -w 4 -b 0.0.0.0:5000 --access-logfile ~/logs/access.log --error-logfile ~/logs/error.log toutiao.main:app -D
gunicorn -w 4 -b 0.0.0.0:5001 --access-logfile /home/python/logs/access.log --error-logfile /home/python/logs/error.log toutiao.main:app -D
gunicorn 关键字
-w 进程数量
-b 绑定的ip和端口
--access-logfile ~/logs/access.log 访问日志存储位置
--error-logfile ~/logs/error.log 错误日志存储位置
toutiao.main 启动文件名
app flask应用对象
-D 守护进程
19-supervisor-进程管理工具
# 1.输出默认的配置项--写入supervisord.conf文件中
echo_supervisord_conf > supervisord.conf
# 2.vim 打开编辑supervisord.conf文件,去掉; 并修改为
[include]
files = /etc/supervisor/*.conf
# 3.将编辑后的supervisord.conf文件复制到/etc/目录下
sudo cp supervisord.conf /etc/
# 4.然后我们在/etc目录下新建子目录supervisor,并且建立头条管理的配置文件toutiao.conf
# 5.启动supervisord
supervisord -c /etc/supervisord.conf
source ~/.bash_profile 刷新脚本文件 ,让脚本文件立即生效
20-supervisorctl客户端使用
# 1.连接supervisorctl客户端
supervisorctl
> status # 查看程序状态
> start apscheduler # 启动 apscheduler 单一程序
> stop toutiao:* # 关闭 toutiao组 程序
> start toutiao:* # 启动 toutiao组 程序
> restart toutiao:* # 重启 toutiao组 程序
> update # 重启配置文件修改过的程序