Elasticsearch概述
- ElasticSearch:基于Lucene的搜索服务器,分布式全文搜索引擎,基于RESTful web接口,是用Java语言开发的。
安装&启动Elasticsearch(这里的所有安装都是在Linux下进行的)
- 安装:
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.9.0-linux-x86_64.tar.gz
运行此命令即可 - 解压:
tar -zxvf elasticsearch-7.9.0-linux-x86_64.tar.gz -C /home
- 解压&启动
- 进入elasticsearch目录 :
cd /home/elasticsearch-7.9.0/bin
- 启动elasticsearch:
./elasticsearch
报错:因为JDK版本不对,7版本的elasticsearch要求最低是11版本的JDK,我们 环境变量的JDK一般都是1.8版本
es5版本需要JDK8以上
es6版本开始支持JDK11
es7版本,内置JDK环境
报错了,那就使用Elasticsearch内置的JDK
- 进入elasticsearch目录 :
vim /home/elasticsearch-7.9.0/bin/elasticsearch-env
打开这个配置文件后找到如下代码:
now set the path to java
if [ ! -z "$JAVA_HOME" ]; then
JAVA="$JAVA_HOME/bin/java"
JAVA_TYPE="JAVA_HOME"
else
if [ "$(uname -s)"="Darwin" ]; then
# macOS has a different structure
JAVA="$ES_HOME"/jdk.app/Contents/Home/bin/java"
else
JAVA="$ES_HOME/jdk/bin/java"
fi
JAVA_TYPE="bundled jdk"
#fi
改造为:
# now set the path to java
# if [ ! -z "$JAVA_HOME" ]; then
# JAVA="$JAVA_HOME/bin/java"
# JAVA_TYPE="JAVA_HOME"
#else
if [ "$(uname -s)"="Darwin" ]; then
# macOS has a different structure
JAVA="$ES_HOME"/jdk.app/Contents/Home/bin/java"
else
JAVA="$ES_HOME/jdk/bin/java"
fi
JAVA_TYPE="bundled jdk"
#fi
意思是将运行的jdk直接配置为内置的jdk,不在找环境变量中jdk
- 新建一个普通用户
- 添加一个用户,用户名就是elasticsearch(自己随意取即可)
adduser elasticsearch
- 为该用户设置密码,会输入两次密码(这里我使用cheng123456,也是随意取)
password elasticsearch //(你自己设置的用户名。我这是elasticsearch)
- 将elasticsearch目录的所有者和所属组改为elasticsearch用户,记得先进入bin目录
[root@....... bin] chwon -R elasticsearch:elasticsearch /home/elasticsearch-7.9.0/
- 配置elasticsearch需要的硬件和软件参数
- 修改打开的最大文件数和族弟啊进程数
vim /etc/security/limits.conf
在该配置文件加:
* soft nofile 65535
* hard nofile 65535
* soft nproc 4096
* hard nproc 4096
- 修改elasticsearch 拥有的内存数(调大)
vim /etc/sysctl.conf 加或改为vm.max_map_count=655360 //记不清了
sysctl -p //检查是否修改成功
- 设置切换到普通用户利用sudo执行root权限的命令免密码输入
执行下面两条指令:
chmod +w /etc/sudoers
vim /etc/sudoers
要改的代码:
elasticsearch ALL=(ALL) NOPASSWD: ALL
%admin ALL=(ALL) NOPASSWD: ALL
- 开放端口
#开放elasticsearch的9300的TCP协议端口
sudo firewall-cmd --zone=public --add-port=9300/tcp --permanent
sudo systemctl restart firewalld.service
sudo firewall-cmd --reload
- 切换到elasticsearch配置并启动
su elasticsearch
- 修改elasticsearch.yml文件,允许所有IP访问
vim /home/elasticsearch7.9.0/config/elasticsearch.yml
//要修改的内容:
network.host: 0.0.0.0
node.name: node-1
cluster.initial_master_nodes: ["node-1"]
- 进入elasticsearch的bin目录启动,第一次启动比较慢,耐心等待
cd /home/elasticsearch-7.9.0/bin/ //进入目录
./elasticsearch //启动elasticsearch
如果没报错就可以访问了:
访问格式:elasticsearch所在主机:9200
以后台的方式启动:./elasticsearch -d
访问成功后的页面:
Kibana概述
- Kibana是一个开源的
分析
和可视化
平台,设计用于和Elasticsearch
一起工作。你用Kibana来搜索,查看,并和存储在Elasticsearch索引中的数据进行交互。你可以轻松地执行高级数据分析,并且以各种图标、表格和地图的形式可视化数据。Kibana使得理解大量数据变得很容易。它简单的、基于浏览器的界面使你能够快速创建和共享动态仪表板,实时显示Elasticsearch查询的变化
。
安装&启动Kibana
- 下载
wget https://artifacts.elastic.co/downloads/kibana/kibana-7.9.0-linuxx86_64.tar.gz
- 解压
sudo tar -zxvf kibana-7.9.0-linux-x86_64.tar.gz -C /home
- 改变kibana解压目录所属用户和所属组
chown -R elasticsearch:elasticsearch kibana-7.9.0/ //这里因为之前添加的用户名叫elasticsearch,所以这里是elasticsearch
- 文件夹授权当前用户和当前用户所属组的读写和执行权限
chmod 770 kibana-7.9.0/
- #切换到elasticsearch用户
su elasticsearch
- 修改配置允许远程访问
vim /home/kibana-7.9.0/config/kibana.yml
server.host: "0.0.0.0"
- 启动Kibana
./home/kibana-7.9.0/bin/kibana
启动成功界面:
访问:Kibana所在主机名:5601
- 使kibana在后台启动,并且将标准输出和错误输出到kibana.log
nohup /home/kibana-7.9.0/bin/kibana > /home/kibana-7.9.0/kibana.log 2>&1 &
访问成功界面:
注:我们在开发中一般是去Kibana的Dev todo 这里进行数据的操作
ES基本概念
1.Document(文档)
- 特征
- document是es可以被搜索的最小单元,可以将其类比为mysql中某张表的一条数据;
- document包含多个(Field)字段,每个字段都有类型(字符串,数值,布尔,日期等);
- document数据以json格式存储在ES中
- 每个document对应一个唯一id,可以自定指定或者由ES自动生成
- 元数据
- _index: 文档所属索引名称。
- _type: 文档所属类型名。
- _id: Doc的主键。在写入的时候,可以指定该Doc的ID值,如果不指定,则系统自动生成一个唯一的UUID值。
- _version: 文档的版本信息。ES通过使用version来保证对文档的变更能以正确的顺序执行,避免乱序造成的数据丢失。
- found:标识查询的ID是否正确,如果为ture,代表查询正确,如果为false,查询不到数据
- _source:文档的原始JSON数据。(创建的数据都在这里面)
2.index(索引)
Index,索引,是文档(Document)的容器,是一类文档的集合。
ElasticSearch将它的数据存储在一个或多个索引(index)中。索引就像数据库,可以向索引写入文档
或者从索引中读取文档
index1(docment1,document2,document3…),index2(document1,document2,document3…)
索引这个词在 ElasticSearch 会有两种意思:
- 索引(名词):
- 类比传统的关系型数据库领域来说,索引相当于SQL中的一个数据库(Database)。索引由其名称(必须为全小写字符)进行标识。
- 索引(名词)
- 保存一个文档到索引的过程。这非常类似于SQL语句中的 INSERT关键词。如果该文档已存在时那就相当于数据库的UPDATE。
注:索引名必须小写,不能以下划线开头,不能包含逗号
- 保存一个文档到索引的过程。这非常类似于SQL语句中的 INSERT关键词。如果该文档已存在时那就相当于数据库的UPDATE。
3.type(类型)
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个电商平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为订单数据定义另一个类型,当然,也可以为商品数据定义另一个类型。
从ES 6.0开始,Type已经过时,7.0开始一个索引只能创建一个type:“_doc”
4.Mapping映射
它就是处理es里面数据的一些使用规则设置也叫做映射.类比字段约束
5.概念类比(关系型数据库与es类比)
ES的CRUD操作
创建文档
- index创建方式
- 创建的书写格式:请求方式 http:主机:端口/索引名/类型/文档ID
如果文档ID不存在,创建新的文档
如果文档ID已经存在。则新创建的文档会覆盖掉旧的文档,同时版本号会增加
- 创建的书写格式:请求方式 http:主机:端口/索引名/类型/文档ID
//在要查询的格式前光标锁定,然后Ctrl+/,可以打开具体的API描述
PUT products/_doc/1
{
"brand_name":"华为",
"product_namw":"meta 30",
"price":4999.99
}
鼠标放在请求行,点击运行即可创建文档
查看文档
GET products/_doc/1
- 如果使用相同id名又创建了一次,比如
PUT products/_doc/101
{
"brand_name":"vivo",
"product_namw":"vivo Y77",
"price":4999.99
}
那内容就会改变为后面这次的创建的,前面的就被覆盖了
- create方式进行创建
- 该方法进行创建,如果ID已经存在,再次创建,会失败报错。
- 有两种创建方式:
1.使用POST提交方式,自动生成文档ID
2.指定文档ID
### 下面的写法等效于=> PUT users/_doc/101?op_type=create
PUT users/_create/10
{
"name":"成c",
"age":19
}
//自动生成document唯一id
POST users/_doc
{
"name":"lisi",
"email":"2345456@qq.com"
}
//指定文档id存在。创建报错
PUT users/_create/10
{
"name":"12成c",
"age":23
}
查询文档
两种:根据id查询,更上面的查询一样
还有就是查询索引下的所有document
//查询users下的所有document
GET users/_search
//根据id查
GET products/_doc/1
更新文档
更新文档必须存在,更新时只对相应字段进行增量修改
- 修改document,添加字段或者更新数据
POST products/_update/1
{
"produc_name":"小米10", //更新字段数据
"product_stock":100 //添加此字段你
}
//使用内置脚本进行更新,这里更新price字段
POST products/_update/1
{
"script":{
"source":"ctx._source.price += params.price",
"lang":"paniless",
"params":{
"price":2999
}
}
}
删除操作
根据id删除
DELETE users/_doc/1
//直接删除索引
DELETE users
批量操作
批量增删改
blu关键字
POST /_bulk
{ "create": { "_index": "website", "_id": "1" }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_id": "2" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_id": "1"} }
{ "doc" : {"title" : "My updated blog post"} }
{ "delete": { "_index": "website", "_id": "1" }}
批量操作的各个操作互补影响,会将每一条操作成功或失败结构返回
批量查询
GET_mget
{
"docs":[
{ "_index":"users",
"id":"101"
},
{
"_index":"prodcuts",
"id":"1"
}
]
}
ES分词&查询
分词和查询那肯定是并用的啦,我们在搜索框输入的一个词或者一句话,都是经过分词后再去查询的,所以查询结果会有几千条
- 分词概述:分词是将文本转换成一系列单词(Term or Token)的过程,也可以叫文本分析,在ES里面称为Analysis
- 分词器是ES中专门处理分词的组件,英文为Analyzer
组成如下:
Character Filters:针对原始文本进行处理,比如去除html标签
Tokenizer:将原始文本按照一定规则切分为单词
Token Filters:针对Tokenizer处理的单词进行再加工,比如转小写、删除或增新等处理
内置分词器
Standard Analysis —— 默认分词器,按词切分,小写处理,停用词会被保留(无意义的词)
Simple Analyzer - 按照非字母切分(非字母会被被过滤)
Stop Analyzer - 小写处理,停用词过滤(the ,a,is)
Whitespace Analyzer - 按照空格切分,不转小写
Keyword Analyzer - 不分词,直接将输入当做输出
Pattern Analyzer - 正则表达式,默认 \W+
Language - 提供了 30 多种常见语言的分词器
Customer Analyzer - 自定义分词器
//Standard Analysis
GET _analyze
{
"analyzer":"standard", //指定分词器
"test":"I am writing code to the sea" //要进行分词的句子
}
//SimpleAnalysis
GET _analyze
{
"analyzer":"simple", //指定分词器
"test":"I am writing code C++ plus 123" //要进行分词的句子
}
//.....其他的写法都是一样的
//language
GET _analyze
{
"analyzer": "english",
"text" : "123 I am flying in the sky"
}
search查询
- 数据准备,这里用批量创建文档的方式
POST /_bluk
{ "create": { "_index": "books", "_id": "100" }}
{ "title": "Java编程思想(第4版)","comment":"就这个快递,我就想给满星,京东快递就是
不一样,我在村里,直接给我送到村里了,别的还得去,镇里去拿,书我还没看,包装的很好,非常适合
提升技术"}
{ "create": { "_index": "books", "_id": "101" }}
{ "title": "Python网络爬虫权威指南 第2版(图灵出品)","comment":"非常棒的一本书,很
适合初学者!" }
{ "create": { "_index": "books", "_id": "102" }}
{ "title": "effective java","comment":"书不错,是正版,对技术提升很有帮助,需要
耐心的把这本书给读透" }
- URL查询
GET books/_search?q=java&df=title
//books:在books索引查询
//q=java:查询内容
//df=title:在title字段上查询
//获取结果从0索引开始总共1条数据,进行分页
POST books/_search?q=java&df=title&from=0&size=1
- JSON查询
- term按照关键字匹配,查询的内容不会被分词
//查询的内容不会被分词,会直接去匹配内容中分词的token
POST books/-search
{
"query":{
"term":{
"title":"java"
}
}
}
。query_string查询,查询内容会被分词
#查询内容也会被分词:java,编,程
GET books/_search
{
"query": {
"query_string": {
"default_field": "title",
"query": "java编程"
}
}
}
ES整合IKAnalyzer
- 下载&安装
由于ES自带的分词器不能很好的支持中文的分词,所以我们考虑集成一款强大的中文分词器来优化我们中文的查询,而且可以自定义词典
//切换到elasticsearch用户
su elasticsearch
//进入es的plugins目录
cd /home/elasticsearch-7.9.0/plugins/
//下载,注意ES的版本和IK的版本的对应
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.9.0/elasticsearch-analysis-ik-7.9.0.zip
//安装unzip命令,用来解压zip压缩包
sudo yum -y install zip unzip
//解压到plugins目录下
unzip elasticsearch-analysis-ik-7.9.0.zip -d IK-7.9.0
//删除该压缩包,防止ES启动加载到报错
rm -rf *.zip
//查看elastic相关进程
ps -ef|grep elastic
//结束es和Kibana
kill -9 8159 10373 //注意这里的进程每次都是不一样的,看自己的进程是什么
//重启es
/home/elasticsearch-7.9.0/bin/elasticsearch -d
//重启Kibana
nohup /home/kibana-7.9.0/bin/kibana > kibana-7.9.0/kibana.log 2>&1 &
测试
IK提供两种分词方法:一种是ik_smart还有一种是 ik_max_word
- ik_max_word 会将文本做最细粒度的拆分
比如会将「中国是世界上最安全的国家」拆分为:中国 国是 世界上 世界 上 最 安全 的 国家 ; - ik_smart 最粗粒度的拆分
比如会将「中国是世界上最安全的国家」拆分为: 中 国是 世界上 最 安全 的 国家。
//删除原有的books索引
DELETE books
//通过mapping指定分析器
PUT books
{
"mappings":{
"properties": {
"title":{
"type":"text",
"analyzer":"ik_smart"
},
"comment":{
"type":"text",
"analyzer":"ik_smart"
}
}
}
}
//查看mapping是否设置成功
GET books/_mapping
//重新新建document
POST /_bulk
{ "create": { "_index": "books", "_id": "100" }}
{ "title": "Java编程思想(第4版)","comment":"就这个快递,我就想给满星,京东快递就是不一
样,我在村里,直接给我送到村里了,别的还得去,镇里去拿,书我还没看,包装的很好,非常适合提升技
术"}
{ "create": { "_index": "books", "_id": "101" }}
{ "title": "Python网络爬虫权威指南 第2版(图灵出品)","comment":"非常棒的一本书,很适合
初学者!" }
{ "create": { "_index": "books", "_id": "102" }}
{ "title": "effective java","comment":"书不错,是正版,对技术提升很有帮助,需要耐心的
把这本书给读透" }
进行查询
POST books/_search
{
"query":{
"term": {
"title": "编程"
}
}
}
自定义词典和停用词
-
配置目录
IKAnalyzer.cfg.xml:用来配置自定义词库
main.dic:ik 原生内置的中文词库,总共有 27 万多条,只要是这些单词,都会被分在一起
quantifier.dic:放了一些单位相关的词
suffix.dic:放了一些后缀
surname.dic:中国的姓氏
stopword.dic:英文停用词
IK分词器还提供了额外的词库补充文件,extra开头的那几个就是,如extra_main.dic,共收录398716条现有的词语,默认没有使用,有需要可以在配置文件IKAnalyzer.cfg.xml上添加,其他类似。 -
自定义词典和停用词
- 在config目录下新建myconfig目录,然后创建my.dic和my_stopword.dic
my.dic(词典):
java语言
python网络爬虫
my_stopword.dic(停用词):
的
了
哈
嘿 - 修改 IKAnalyzer.cfg.xml
- 在config目录下新建myconfig目录,然后创建my.dic和my_stopword.dic
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">myconfig/my.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">myconfig/my_stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
- 重启es和Kibana
//查看elastic相关进程
ps -ef|grep elastic
//结束es和kibana进程
kill -9 8159 10373
//重启es
/home/elasticsearch-7.9.0/bin/elasticsearch -d
//重启kibana
nohup /home/kibana-7.9.0/bin/kibana > kibana-7.9.0/kibana.log 2>&1 &
- 查询测试
//需要删除重新创建mapping
DELETE books
PUT books
{
"mappings":{
"properties": {
"title":{
"type":"text",
"analyzer":"ik_smart"
},
"comment":{
"type":"text",
"analyzer":"ik_smart"
}
}
}
//创建document
POST /_bulk
{ "create": { "_index": "books", "_id": "100" }}
{ "title": "Java编程思想(第4版)","comment":"就这个快递,我就想给满星,京东快
递就是不一样,我在村里,直接给我送到村里了,别的还得去,镇里去拿,书我还没看,包装的很
好,非常适合提升技术"}
{ "create": { "_index": "books", "_id": "101" }}
{ "title": "Python网络爬虫权威指南 第2版(图灵出品)","comment":"非常棒的一本
书,很适合初学者!" }
{ "create": { "_index": "books", "_id": "102" }}
{ "title": "effective java","comment":"书不错,是正版,对技术提升很有帮助,
需要耐心的把这本书给读透" }
//term查询
POST books/_search
{
"query":{
"term": {
"title": "java语言"
}
}
}
POST books/_search
{
"query":{
"term": {
"title": "python网络爬虫"
}
}
}
ES集群搭建
分片&副本
- 索引可以存储大量的数据,这些数据可能超过单个节点的硬件限制。例如,十亿个文件占用磁盘空间1TB的单指标可能不适合对单个节点的磁盘或可能太慢服务仅从单个节点的搜索请求.为了解决这一问题,Elasticsearch提供细分你的指标分成多个块称为分片的能力。当你创建一个索引,你可以简单地定义你想要的分片数量。每个分片本身是一个全功能的、独立的“指数”,可以托管在集群中的任何节点。也就是一台机器完不成的,或者难度复杂度很高的,就要利用集群来完成
- 在同一个集群网络或云环境上,故障是任何时候都会出现的,拥有一个故障转移机制以防分片和结点因为某些原因离线或消失是非常有用的,并且被强烈推荐。为此,Elasticsearch允许你创建一个或多个拷贝,你的索引分片进入所谓的副本或称作复制品的分片,简称Replicas。
目的就是防止当一个节点挂了,导致其他节点也全挂了,有副本就不会出现全部崩了的情况
配置并启动三台ES节点
- 准备三台虚拟机来进行实现,每台都直接拷贝之前安装好ES和Kibana的那台虚拟机就OK了
- 这里就命名为es-01,es-02,es-03,命名是自定义的
- 修改es-01的elasticsearch.yml
末尾加:
cluster.name: es
node.name: es-01
path.data: /home/elasticsearch/data
path.logs: /home/elasticsearch/logs
network.host: 192.168.1.155
discovery.seed_hosts:
["192.168.1.155:9300","192.168.1.217:9300","192.168.1.117:9300"]
cluster.initial_master_nodes: ["es-01", "es-02", "es-03"]
xpack.monitoring.collection.enabled: true
- 修改es-02的elasticsearch.yml
cluster.name: es
node.name: es-01
path.data: /home/elasticsearch/data
path.logs: /home/elasticsearch/logs
network.host: 192.168.1.217
discovery.seed_hosts:
["192.168.1.155:9300","192.168.1.217:9300","192.168.1.117:9300"]
cluster.initial_master_nodes: ["es-01", "es-02", "es-03"]
xpack.monitoring.collection.enabled: true
- 修改es-03的elasticsearch.yml
cluster.name: es
node.name: es-01
path.data: /home/elasticsearch/data
path.logs: /home/elasticsearch/logs
network.host: 192.168.1.117
discovery.seed_hosts:
["192.168.1.155:9300","192.168.1.217:9300","192.168.1.117:9300"]
cluster.initial_master_nodes: ["es-01", "es-02", "es-03"]
xpack.monitoring.collection.enabled: true
其中的各个参数的解释:
- cluster.name:集群的名称,集群中所有节点的 cluster.name 的值必须要相同。
- node.name:集群中每个Elasticsearch的节点名称,不可以重复。
- path.data:设置存放Elasticsearch索引文件数据的路径。
- path.logs:设置存放日志文件的路径。
- network.host:Elasticsearch绑定的IP,外界可以通过这个IP访问到当前Elasticsearch节点,一般配配置当前系统的IP,或者 0.0.0.0 (任何地址都能访问到)。
- http.port:当前启动Elasticsearch的端口号,一般默认 9200 即可,当然你也可以修改
- discovery.seed_hosts:配置所有Elasticsearch节点绑定的IP地址。
- cluster.initial_master_nodes:配置那些节点可以有资格被选为主节点。
- xpack.monitoring.collection.enabled:收集监控数据默认为false不收集监控数据。
注:其中的主机名都是按照自己的来写
- 在es-01、es-02、es-03的/home/elasticsearch下创建data和logs目录
mkdir data
mkdir logs
- 三台机器分别执行es启动
后台启动
/home/elasticsearch-7.9.0/bin/elasticsearch -d
ES集群整合 cerebro
- cerebro是一个开源(MIT许可)elasticsearch web管理工具,使用Scala、Play Framework、AngularJS和Bootstrap构建。cerebro的运行需要java1.8及以上版本。
- 在es-01机器上执行如下操作
//授权
sudo chmod 777 /home
//下载
wget https://github.com/lmenezes/cerebro/releases/download/v0.9.2/cerebro0.9.2.tgz
//解压
tar -zxvf cerebro-0.9.2/bin/cerebro > /home/cerebro-0.9.2/cerebro.log 2>&1 &
//开放cerebro的默认访问端口9000
firewall-cmd --zone=public --add-port=9000/tcp --permanent
systemctl restart firewalld.service
firewall-cmd --reload
填写主机名即可连接
集群整合Kibana
- 修改es-01上的kibana配置文件kibana.yml
server.host: "192.168.1.155" //es-01的主机IP
elasticsearch.hosts:
["http://192.168.1.155:9200","http://192.168.1.217:9200","http://192.168.1.1
17:9200"]
- 启动Kibana
nohup /home/kibana-7.9.0/bin/kibana > /home/kibana-7.9.0/kibana.log 2>&1 &
- 访问Kibana的dev tools
//查看集群健康状况
GET _cluster/health
//查看分片和副本情况
GET _cat/shards
- 创建索引、指定分配和副本
PUT /books
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
POST /_bulk
{ "create": { "_index": "books", "_id": "100" }}
{ "title": "Java编程思想(第4版)","comment":"就这个快递,我就想给满星,京东快递就是
不一样,我在村里,直接给我送到村里了,别的还得去,镇里去拿,书我还没看,包装的很好,非常适合
提升技术"}
{ "create": { "_index": "books", "_id": "101" }}
{ "title": "Python网络爬虫权威指南 第2版(图灵出品)","comment":"非常棒的一本书,很
适合初学者!" }
{ "create": { "_index": "books", "_id": "102" }}
{ "title": "effective java","comment":"书不错,是正版,对技术提升很有帮助,需要
耐心的把这本书给读透" }
- 停止其中一台es测试是否能获取数据
GET books/_doc/100
说明:不管如何,它都会自动配置完全的012三台机器运行着
复杂查询
多字段查询
- 创建索引
PUT books
{
"mappings":{
"properties": {
"title":{
"type":"text",
"analyzer":"ik_smart" //指定分词器
},
"comment":{
"type":"text",
"analyzer":"ik_smart" //指定分词器
}
}
}
}
- 创建document
POST /_bulk
{ "create": { "_index": "books", "_id": "100" }}
{ "title": "Java编程思想(第4版)","comment":"就这个快递,我就想给满星,京东快递就是不一
样,我在村里,直接给我送到村里了,别的还得去,镇里去拿,书我还没看,包装的很好,非常适合提升技
术"}
{ "create": { "_index": "books", "_id": "101" }}
{ "title": "Python网络爬虫权威指南 第2版(图灵出品)","comment":"非常棒的一本书,很适合
初学者!" }
{ "create": { "_index": "books", "_id": "102" }}
{ "title": "effective java","comment":"书不错,是正版,对技术提升很有帮助,需要耐心的
把这本书给读透" }
- 多字段查询
//title:java编程 OR comment:java编程 ,这两个查询条件之间是或的关系,满足一个就可以命中
POST books/_search
{
"query": {
"query_string": {
"fields": ["title","comment"],
"query": "Java编程"
}
}
}
(title:java编程 OR comment:java编程) AND (title:技术 OR comment:技术) ,这里的查询条件就是and,两边都要满足才会被命中
POST books/_search
{
"query": {
"query_string": {
"fields": ["title","comment"],
"query": "Java编程 AND 技术"
}
}
}
(title:java编程 OR comment:java编程) OR (title:技术 OR comment:技术) ,这里的查询条件就是or,满足一边就会命中
POST books/_search
{
"query": {
"query_string": {
"fields": ["title","comment"],
"query": "Java编程 OR 技术"
}
}
}
Boolean 查询
布尔查
询是最常用的组合查询,不仅将多个查询条件组合在一起,并且将查询的结果和结果的评分组合在一起。当查询条件是多个表达式的组合时,布尔查询非常有用,实际上,布尔查询把多个子查询组合(combine)成一个布尔表达式,所有子查询之间的逻辑关系是与(and);只有当一个文档满足布尔查询中的所有子查询条件时,ElasticSearch引擎才认为该文档满足查询条件。布尔查询支持的子查询类型共有四种,分别是:must,should,must_not和filter:
- must子句:文档必须匹配must查询条件,会影响score;
- should子句:文档应该匹配should子句查询的一个或多个,会影响score;当没有指定must子句的时候,should至少满足一个条件
- must_not子句:文档不能匹配该查询条件,不影响score
- filter子句:过滤器,文档必须匹配该过滤条件,跟must子句的唯一区别是,filter不影响查询的score;
- 注:每个子句中可以包含多个查询条件(例如:term查询或者query_string等),must,should,must_not,filter之间可以相互嵌套
- 创建五个document:
POST /_bulk
{ "create": { "_index": "products", "_id": "300" }}
{ "name": "小米手机","brand":"小米","price":"3000","status":"0"}
{ "create": { "_index": "products", "_id": "400"}}
{ "name": "松下洗衣机","brand":"松下","price":"3999","status":"1" }
{ "create": { "_index": "products", "_id": "500" }}
{ "name": "华为手机", "brand":"华为","price":"5999","status":"1"}
{ "create": { "_index": "products", "_id": "600" }}
{ "name": "松下电饭煲", "brand":"松下","price":"1999","status":"0"}
{ "create": { "_index": "products", "_id": "700" }}
{ "name": "联想笔记本", "brand":"联想","price":"7999","status":"1"}
- query_string查询
POST products/_search
{
"query": {
"bool": {
"must":
{
"query_string": {
"default_field": "brand",
"query": "松下"
}
},
"filter":
{
"term": {
"status": "1"
}
}
}
}
}
- Boolean查询
POST products/_search
{
"query": {
"bool": {
"must_not": [ //must子句
{
"query_string": {
"default_field": "name", //查询字段
"query": "松下" //查询内容
}
}
],
"should": [ //should子句
{
"range": {
"price": { //查询字段
"gte": 3000,
"lte": 6000
//区间为3000~6000
}
}
},
{
"term": {
"status":"0"
}
}
]
}
}
}
logstash数据采集
概述:
- logstash作为Elasicsearch常用的实时数据采集引擎,可以采集来自不同数据源的数据,并对数据进行处理后输出到多种输出源,是Elastic Stack 的重要组成部分.
- logstash的数据处理过程主要包括:Inputs, Filters, Outputs 三部分, 另外在Inputs和Outputs中可以使用Codecs对数据格式进行处理。这三个部分均以插件形式存在,用户通过定义pipeline配置文件,设置需要使用的input,filter,output, codec插件,以实现特定的数据采集,数据处理,数据输出等功能
Inputs:用于从数据源获取数据,例如:redis,mysql,syslog,rabbitmq,…
Filters:用于处理数据如格式转换等
Outputs:用于数据输出,例如:MongoDB,HDFS,ElasticSearch
安装与启动
cd /home
wget https://artifacts.elastic.co/downloads/logstash/logstash-7.9.0.tar.gz
tar -zxvf logstash-7.9.0.tar.gz
测试
//使用临时配置,input:标准控制台输入 output:标准控制台输出
/home/logstash-7.9.0/bin/logstash -e 'input { stdin { } } output { stdout {} }'
输入hello stash会得到此输出:
将MySQL数据库中的数据导入ES中
- logstash配置:
input {
jdbc {
jdbc_driver_library => "/home/jar/mysql-connector-java-5.1.49.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://x.x.x.x:3306/es_test"
jdbc_user => "root"
jdbc_password => "123456"
statement => "SELECT * FROM t_book"
}
}
output {
elasticsearch {
index => "t_books"
hosts => ["x.x.x.x:9200"]
document_id => "%{book_id}"
template_name => "logstash"
template => "/home/template/logstash.json"
}
}
{
"index_patterns": ["t_books"],
"mappings": {
"date_detection": true,
"numeric_detection": true,
"dynamic_templates": [
{
"string_fields": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false,
"analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
]
}
}
- 上传mysql的驱动jar包和logstash的配置文件,然后将logstash以配置文件启动
//mkdir jar,存放MySQLjar包
//mkdir template ,存放logstash配置文件
//启动logstash
logstash-7.9.0/bin/logstash -f /home/logstash-7.9.0/config/logstashmysql.conf
- 在Kibana中查询导入的数据
ES整合Spring Boot
Spring Data概述
- 对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。
- Spring Boot 添加了大量自动配置,屏蔽了很多设置,引入各种 XxxTemplate,XxxRepository 来简化程序员对数据访问层的操作。对程序员来说只需要进行简单的配置即可使用
- Spring Data 是一个用于简化数据库访问的开源框架,支持访问关系型数据库、非关系型数据库 云计算服务等。
增删改操作
- 创建springboot-elasticsearch工程,引入依赖
要加一个elasticsearch的依赖
加一个插件,用来连elasticsearch
– Elasticsearch连接
在pom.xml中加这个依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
- 创建实体类与es的索引进行绑定
package com.example.elasticsearch.pojo;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Document(indexName = "users")
public class Users {
@Id
private Integer id; //文档id
@Field(type = FieldType.Text)
private String username; //type = FieldType.Text:指定字段的类型
@Field(type = FieldType.Text)
private String password;
public Users() {
}
public Users(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
- 创建相应的接口
public interface UserService extends ElasticsearchRepository<Users,Integer> {
}
- 创建测试类(CRUD)
@SpringBootTest
class UserServiceTest {
@Autowired
ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired
UserService userService;
/*
* 创建索引
* */
@Test
public void testCreateIndex(){
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Users.class);
}
/*
* 删除索引
* */
@Test
public void testDeleteIndex(){
elasticsearchRestTemplate.indexOps(Users.class).delete();
}
/*
* 向索引中添加文档
* */
@Test
public void saveDoc(){
//通过elasticsearchRestTemplate添加
elasticsearchRestTemplate.save(new Users(101,"韩梅梅","123456"));
//通过xxxService添加
userService.save(new Users(100,"成成","3243535"));
}
/*
* 向索引中批量添加文档
* */
@Test
public void saveBatchDoc(){
List<Users> users = Arrays.asList(new Users(002,"zhangsan","000021")
,new Users(021,"lisi","456456"));
elasticsearchRestTemplate.save(users);
}
/**
* 根据id删除文档
*/
@Test
public void delDocById() {
userService.deleteById(002);
}
/**
* 根据id去更新数据
*/
@Test
public void updateDoc() {
userService.save(new Users(021, "李四","00432"));
}
}
基础操作
- 基本查询
- 创建实体类
package com.example.elasticsearch.pojo;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.math.BigDecimal;
@Document(indexName = "t_books") //绑定es的索引
public class Book {
/**
* 书编号
*/
@Id
private Integer bookId;
/**
* 书名称
*/
@Field(type = FieldType.Text, analyzer = "ik_smart", name = "book_name")
private String bookName;
/**
* 单价
*/
@Field(type = FieldType.Double, name = "book_price")
private BigDecimal bookPrice;
/**
* 库存
*/
@Field(type = FieldType.Integer,name="book_stock")
private Integer bookStock;
/**
* 描述
*/
@Field(type=FieldType.Text,analyzer = "ik_smart",name =
"book_description")
private String bookDescription;
public Book() {
}
public Book(Integer bookId, String bookName, BigDecimal bookPrice, Integer bookStock, String bookDescription) {
this.bookId = bookId;
this.bookName = bookName;
this.bookPrice = bookPrice;
this.bookStock = bookStock;
this.bookDescription = bookDescription;
}
public Integer getBookId() {
return bookId;
}
public void setBookId(Integer bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public BigDecimal getBookPrice() {
return bookPrice;
}
public void setBookPrice(BigDecimal bookPrice) {
this.bookPrice = bookPrice;
}
public Integer getBookStock() {
return bookStock;
}
public void setBookStock(Integer bookStock) {
this.bookStock = bookStock;
}
public String getBookDescription() {
return bookDescription;
}
public void setBookDescription(String bookDescription) {
this.bookDescription = bookDescription;
}
@Override
public String toString() {
return "Book{" +
"bookId=" + bookId +
", bookName='" + bookName + '\'' +
", bookPrice=" + bookPrice +
", bookStock=" + bookStock +
", bookDescription='" + bookDescription + '\'' +
'}';
}
}
- 创建BookService接口
package com.example.elasticsearch.Service;
import com.example.elasticsearch.pojo.Book;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface BookService extends ElasticsearchRepository<Book,Long> {
}
- 测试类
package com.example.elasticsearch.Service;
import com.example.elasticsearch.pojo.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
@SpringBootTest
class BookServiceTest {
@Autowired
ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired
BookService bookService;
/*
* 查询所有文档
* */
@Test
public void findAll(){
Iterable<Book> books = bookService.findAll();
books.forEach(System.out::println);
}
/*
* 根据文档id查询
* */
@Test
public void testFindBuId(){
System.out.println(bookService.findById(16L).get());
}
}
模板方法查询
- 在接口定义好相应的方法,直接调用就可以
public interface BookService extends ElasticsearchRepository<Book,Long> {
/**
* 根据书名查询
* @return
*/
List<Book> findByBookName(String bookName);
/**
* 根据标题或描述查询
*/
List<Book> findByBookNameAndBookDescription(String bookName, String
bookDescription);
}
- 测试类
@SpringBootTest
class BookServiceTest02 {
@Autowired
ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired
BookService bookService;
/**
* 根据书名查询
* POST t_books/_search
* {
* "query": {
* "query_string": {
* "default_field": "book_name",
* "query":"Elasticsearch实战"
* , "default_operator": "AND"
* }
* }
* }
*/
@Test
public void testFindByBookName() {
//bookRepository.findByBookName("java编程").forEach(System.out::println);
//bookRepository.findByBookName("Elasticsearch实
战").forEach(System.out::println);
bookRepository.findByBookName("实战
Elasticsearch").forEach(System.out::println);//分词后是"实战" And "Elasticsearch"
}
/**
* 根据书名和书描述查询
*/
@Test
public void testFindByNameOrDescription() {
bookRepository.findByBookNameAndBookDescription("java", "java")
.forEach(System.out::println);
}
}
分页查询
public interface BookService extends ElasticsearchRepository<Book,Long> {
/**
* 分页查询
*/
List<Book> findByBookNameIn(Collection<String> bookNames, Pageable
pageable);
}
- 测试类
package com.example.elasticsearch.Service;
import com.example.elasticsearch.pojo.Book;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
@SpringBootTest
class BookServiceTest {
@Autowired
ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired
BookService bookService;
/**
* 分页查询
*/
@Test
public void testFindByBookNameIn() {
bookService.findByBookNameIn(Arrays.asList("java", "python",
"spring"), PageRequest.of(0, 10))
.forEach(System.out::println);
}
}
原始查询
- 原始查询相当于把ES中的查询转换成java中的方法
@SpringBootTest
class BookRepositoryTest02 {
@Autowired
ElasticsearchRestTemplate elasticsearchRestTemplate;
/**
* query_string查询
* 需求:查询内容为"java和python",将结果按照书的价格降序排列,取出最终结果的两条数据
*/
@Test
public void testQueryString() {
//1.构建查询方式和查询条件
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.queryStringQuery("java和python"))//指定使用的查询方式
.withSort(SortBuilders.fieldSort("book_price").order(SortOrder.DESC))//排序
.withPageable(PageRequest.of(0,3))
.build();
//2.执行查询
/* SearchHits<Book> bookSearchHits =
elasticsearchRestTemplate.search(searchQuery, Book.class);
for (SearchHit<Book> bookSearchHit : bookSearchHits) {
System.out.println(bookSearchHit.getContent());
}*/
elasticsearchRestTemplate.search(searchQuery, Book.class)
.forEach(bookSearchHit ->
System.out.println(bookSearchHit.getContent()));
}
}
高亮查询
- ES中高亮查询的实现
//ES高亮查询
POST products/_search
{
"query": {
"bool": {
"must":
{
"query_string": {
"default_field": "name",
"query": "松下"
}
}
}
},
"highlight": {
"fields": {
"name": {
"pre_tags": [
"<b>"
],
"post_tags": [
"</b>"
]
}
}
}
}
- JAVA代码实现高亮查询
- 接口中方法书写:
public interface BookRepository extends ElasticsearchRepository<Book,Long> {
/**
* 高亮显示
* @return
*/
@Highlight(fields = {
@HighlightField(name = "bookName"),
@HighlightField(name = "bookDescription")
},parameters = @HighlightParameters(preTags = "<font
sytle='color:red'>",postTags = "</font>"))
List<SearchHit<Book>> findByBookNameOrBookDescription(String bookName,
String bookDescription);
}
- 测试类
@SpringBootTest
class BookRepositoryTest02 {
/**
* 高亮查询
* bookName: xxx 或 bookDescription中有java
*/
@Test
public void testHightlight() {
List<SearchHit<Book>> byBookNameOrBookDescription = bookRepository.
findByBookNameOrBookDescription("java", "java");
for (SearchHit<Book> bookSearchHit : byBookNameOrBookDescription) {
System.out.println("--------------------");
System.out.println(bookSearchHit.getId());
bookSearchHit.getHighlightField("bookName").forEach(s ->
System.out.println("bookName="+s));
bookSearchHit.getHighlightField("bookDescription").forEach(s ->
System.out.println("bookDescription="+s));
System.out.println("---------------------------------");
}
}
}
高亮也就是给命中的内容加HTML标签中的style样式而已!