ElasticSearch 是一个分布式的RESTful开源全文搜索和分析引擎,使用 Java 开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能, 2010 年首次发布。快速,近实时地存储,搜索和分析大量数据。它通常用作底层引擎、技术,为具有复杂搜索功能和要求的应用程序提供支持。
Lucene介绍
Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎,但是 Lucene 操作复杂,一般不直接利用 Lucene 作为搜索引擎,ElasticSearch 就是利用 Java 简化了 Lucene 的使用。
https://www.elastic.co/cn/
通常 Elastic Stack 称为 ELK Stack(代指 Elasticsearch、Logstash 和 Kibana),目前 Elastic Stack 包括一系列丰富的轻量型数据采集代理,这些代理统称为 Beats,可用来向 Elasticsearch 发送数据。
访问地址:
https://www.elastic.co/cn/what-is/elk-stack
Logstash 的用途是什么?
Logstash 是免费且开放的服务器端数据处理管道,能够从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。
Kibana 的用途是什么?
Kibana 是一个免费且开放的用户界面,能够让您对 Elasticsearch 数据进行可视化,并让您在 Elastic Stack 中进行导航。您可以进行各种操作,从跟踪查询负载,到理解请求如何流经您的整个应用,都能轻松完成。
Beats 轻量型数据采集器
Beats 是一个免费且开放的平台,集合了多种单一用途数据采集器。它们从成百上千或成千上万台机器和系统向 Logstash 或 Elasticsearch 发送数据。
Auditbeat 审计数据
Metricbeat 指标数据
Filebeat 日志文件
Packetbeat 网络指标数据
Heartbeat 运行时间监控
Widows beat windows 事件日志
elasticsearch与solr两款产品对比
1)Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;
2)Solr 支持更多格式的数据,HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。而 Elasticsearch 仅支持json文件格式;
3)Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。
4)Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。
5)Solr 查询io阻塞
elasticsear应用场景
全文检索: 淘宝 京东… 海量数据搜索,例如:搜索华为手机
记录和日志分析: 结合Logstash,ElasticSearch 和Kibana 三个组件,可以搭建一套高效的日志收集和分析系统,也就是我们常见的ELK系统。
数据可视化: Kibana 是一款功能强大且易于使用的可视化工具,可以结合 ES 对大量数据提供图表选项、地理数据等可视化组件。
elastic java 版本支持
https://www.elastic.co/cn/support/matrix#matrix_jvm
1、安装java环境,一般是1.8版本
# 查看java的yum包版本
yum list installed grep java*
# 安装java环境
yum install -y java
# 查看安装版本
java -version
该版本已经经过编译,可以在解压后直接使用
# 解压并移动文件
tar xzf elasticsearch-7.12.0-linux-x86_64.tar.gz -C /usr/local/
#root用户是无法启动程序,因此需要创建一个普通用户启动
#创建es用户组
groupadd es
# 为es用户组添加es用户
useradd -g es es
#为es用户设置密码
passwd es
#将elasticsearch-7.12.0目录所有权限切换成es用户的
chown -R es.es /usr/local/elasticsearch-7.12.0/
#切换登录用户为es
su es
# es用户启动并运行程序,-d是后台运行
/usr/local/elasticsearch-7.12.0/bin/elasticsearch -d
# 查看程序端口9200启动情况
netstat -tunlp
# 访问服务
curl 127.0.0.1:9200
修改elastic配置文件使得对外能够访问
# 修改配置文件使得对外能够通过ip地址访问
vi /usr/local/elasticsearch-7.12.0/config/elasticsearch.yml
network.host: 0.0.0.0
cluster.initial_master_nodes: ["node-1"]
# 修改文件描述符
vi /etc/security/limits.conf
# 最后一行新增以下设置
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
# 修改虚拟内存
vi /etc/sysctl.conf
vm.max_map_count=262144
# 执行重新加载内存命令
sysctl -p
# es用户启动并运行程序
/usr/local/elasticsearch-7.12.0/bin/elasticsearch
访问站点:
http://192.168.1.128:9200/
3、kibana安装
下载版本与Elasticsearch对应
# 解压并移动文件,和elasticsearch一样不需要再次编译
tar xzf kibana-7.12.0-linux-x86_64.tar.gz -C /usr/local/
# 修改配置文件
vi /usr/local/kibana-7.12.0-linux-x86_64/config/kibana.yml
#将配置文件内容改为指定elasticsearch的服务ip地址
elasticsearch.hosts: ["http://192.168.1.128:9200"]
server.host: "0.0.0.0"
# 启动服务
/usr/local/kibana-7.12.0-linux-x86_64/bin/kibana --allow-root
访问站点:
http://192.168.1.128:5601
4、elasticsearch-head安装(不怎么适配浏览器,不好用)
elasticsearch-head 是用于监控 Elasticsearch 状态的客户端插件,包括数据可视化、执行增删改查操作等。
插件下载地址:
http://extb.cqttech.com/
9200与9300端口说明
9200 是ES节点与外部通讯使用的端口。它是http协议的RESTful接口(各种CRUD操作都是走的该端口,如查询:http://localhost:9200/user/_search)。
9300是ES节点之间通讯使用的端口。它是tcp通讯端口,集群间和TCPclient都走的它。(java程序中使用ES时,在配置文件中要配置该端口)
倒排索引
ElasticSearch引擎把文档数据写入到倒排索引(Inverted Index)的数据结构中,倒排索引建立的是分词(Term)和文档(Document)之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的。
倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key
常见到的概念
1)index 索引
等同于关系型数据库中的表
2)document 文档
等同于关系型数据库表中的行
3)field 字段
等同于关系型数据库表中的column
4)shard 分片
类似于关系型数据库中的分表,它们共同持有该索引的所有数据
5)replicas 副本
类似于关系型数据库中的主从,每个node一个副本
API文档
https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html
ES索引增删改查
# 创建索引格式
PUT /<index>
# 索引命名格式要求
只能小写
不能包括 \, /, *, ?, ", <, >, |, ` ` (space character), ,, #
不能以 -, _, + 开头
不能 . 或者 ..
ES索引增删改查示例:
#获取所有索引列表
GET /_cat/indices
# 创建test1
PUT /test1
# 创建test2
PUT /test2
{
"settings": {
# 设置分片数
"number_of_shards": 1,
# 设置副本数
"number_of_replicas": 1
}
}
# 创建test3并声明属性和类型
PUT /test3
{
"mappings": {
"properties": {
"name":{"type": "text"},
"age":{"type":"integer"}
}
}
}
# 获取test3索引
GET /test3
# 判断索引是否存在
HEAD /test2
# 删除索引
DELETE /test2
字段类型:
字符串
Text 会分词,然后进行索引 字段要被全文搜索 如商品标题 ..
keyword 不进行分词,直接索引 适用于索引结构化的字段 如商品分类 文章标签
整数
byte short integer long
满足需求的情况下,尽可能选择范围小的数据类型
ES新增、更新、删除文档与获取文档
文档:
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs.html
# 新增文档,未指定id则会生成唯一id /索引名/_doc
POST /test3/_doc
{
"name":"liuyuanshan"
}
# 新增文档,指定id
POST /test3/_doc/1
{
"name":"liuyuanshan",
"age":18
}
# 获取所有文档 /索引/_search
GET /test3/_search
# 获取文档 /索引/_doc/_id
GET /test3/_doc/1
# 更新文档 /索引/_update/_id
POST /test3/_update/1
{
"doc":{
"age":77
}
}
# 获取文档 /索引/_doc/_id
GET /test3/_doc/1
# 删除文档 /索引/_doc/_id
DELETE /test3/_doc/1
# 获取所有文档 /索引/_search
GET /test3/_search
乐观锁悲观锁介绍
悲观锁 常见于关系型数据库,比如mysql
悲观锁的控制方案就是在任何情况下,都上锁,上锁之后只有一个线程可以操作这条数据了。
乐观锁 elastic
乐观锁状态下是不加锁的,每个线程都可以任意操作。依靠数据版本号和自身的是否一致保证数据的一致性。
悲观锁
优点:方便,直接加锁,不需任何操作。
缺点:并发能力低,同一时间只有一个线程可以操作数据
乐观锁
优点:并发能力很高,不用给数据加锁,大量线程并发操作。
缺点:麻烦,每次操作都要校验版本号,这种情况下可能需要重新加载数据,再写,再次修改,可能会持续好几个过程
ES批量操作bulk增删改查
文档:
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
格式说明:
POST /_bulk
{ action: { metadata }}
{ request body }
{ action: { metadata }}
{ request body }
create
如果文档不存在,那么就创建它
index
创建一个新文档或者替换一个现有的文档
update
部分更新一个文档
delete
删除一个文档
metadata 应该指定被索引、创建、更新或者删除的文档的 _index 、 _id
request body 行由文档的 _source 本身组成—文档包含的字段和值,create index update 必须 delete 不需要
案例:
# 创建一个新文档或者替换一个现有的文档test4索引并指定id为1,属性name和age
POST /_bulk
{"index":{"_index":"test4","_id":1}}
{"name":"刘远山","age":18}
{"index":{"_index":"test4","_id":2}}
{"name":"user2","age":22}
# 获取所有文档 /索引/_search
GET /test4/_search
# 批量获取test4文档
GET /test4/_mget
{
"ids":[1,2]
}
# create创建test4索引如果test4存在则报错
POST /_bulk
{"create":{"_index":"test4","_id":3}}
{"name":"user2","age":18}
# update更新test4索引
POST /_bulk
{"update":{"_index":"test4","_id":3}}
{"doc":{"name":"user2","age":18,"mobile":"xxxx"}}
# delete删除test4索引
POST /_bulk
{"delete":{"_index":"test4","_id":3}}
ES中的search主要分为URI Search和Query DSL
ES查询之URI查询
URL查询格式
# 获取所有的
GET /<target>/_search
# 分页查询 scroll
GET /<target>/_search ?size=2&from=1
GET /<target>/_search ?q=age:66
# 获取一条
GET /<target>/_doc/id
# 获取一条中的某个字段
GET /<target>/_doc/id?_source=field1,field2
# 创建test5
POST /_bulk
{"index":{"_index":"test5","_id":1}}
{"name":"user1","age":35,"addr":"山东省青岛市"}
{"index":{"_index":"test5","_id":2}}
{"name":"user2","age":36,"addr":"山东省枣庄市"}
{"index":{"_index":"test5","_id":3}}
{"name":"user3","age":20,"addr":"江苏省南京市"}
{"index":{"_index":"test5","_id":4}}
{"name":"user4","age":23,"addr":"江苏省苏州市"}
{"index":{"_index":"test5","_id":5}}
{"name":"user5","age":20,"addr":"中国北京市"}
# 获取所有文
GET /test5/_search
# 查询age=20的数据
GET /test5/_search?q=age:20
#根据id获取一条数据
GET /test5/_doc/5
#根据id获取一条数据中的某个字段数据
GET /test5/_doc/5?_source=name,age
# 分页查询,从id=2之后的数据开始查询两条
GET /test5/_search?size=2&from=2
DSL查询
虽然使用简单的 GET 参数也可以从 Elasticsearch 获取数据,但要使用强大的查询和聚合功能,查询基于JSON格式DSL (Query Domain Special Language)是必不可少的,这也是官方推荐在生产环境中使用的数据获取方式。
1)排序、分页、大小范围获取数据示例:
# 查询年龄在20到30之间的数据,根据age进行倒序,从id=2之后开始显示两条
POST /test5/_search
{
"query": {
"range":{
"age":{
"gte": 20,
"lte": 50
}
}
},
"from": 2,
"size": 2,
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
2)match查询示例:
match会根据查询的字段进行分词,再进行分词查询、模糊匹配,中文分词是单个分,英文是根据空格分词
查看分词效果
# 查看分词效果
GET /_analyze
{
"tokenizer": "standard",
"text":"山东省"
}
# 创建test5
POST /_bulk
{"index":{"_index":"test5","_id":1}}
{"name":"user1","age":35,"addr":"山东省青岛市"}
{"index":{"_index":"test5","_id":2}}
{"name":"user2","age":36,"addr":"山东省枣庄市"}
{"index":{"_index":"test5","_id":3}}
{"name":"user3","age":20,"addr":"江苏省南京市"}
{"index":{"_index":"test5","_id":4}}
{"name":"user4","age":23,"addr":"江苏省苏州市"}
{"index":{"_index":"test5","_id":5}}
{"name":"user5","age":20,"addr":"中国北京市"}
{"index":{"_index":"test5","_id":6}}
{"name":"user5","age":20,"addr":"hello world"}
# match查询山东省,并显示指定字段
POST /test5/_search
{
"query":{
"match": {
"addr": "山东省"
}
},
"_source": ["name","addr"]
}
# match查询山东省与hello,并显示指定字段
POST /test5/_search
{
"query":{
"multi_match": {
"query": "山东省hello",
"fields": ["addr","name"]
}
}
}
3)term查询
term查询不会对查询的字段进行分词查询,会采用精确匹配。
#查询包含-市
POST /test5/_search
{
"query": {
"term": {
"addr": {
"value": "市"
}
}
}
}
4)highlight高亮查询
# 查询包含-市关键词,同时进行高亮显示成红色字体
POST /test5/_search
{
"query": {
"term": {
"addr": {
"value": "市"
}
}
},
"highlight": {
"fields": {
"addr": {}
},
"tags_schema": "styled",
"pre_tags": [""],
"post_tags": [""]
}
}
中文分词ik安装
下载地址:(要求下载版本号要与es版本号一致elasticsearch-analysis-ik-7.12.0.zip)
https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.12.0
1)解压到指定目录
#进入es插件目录
cd /usr/local/elasticsearch-7.12.0/plugins/
#创建中文分词ik目录
mkdir ik
# 解压文件到指定目录
unzip -n elasticsearch-analysis-ik-7.12.0.zip -d /usr/local/elasticsearch-7.12.0/plugins/ik/
# 设置目录所有者和所属组为es
chown -R es.es /usr/local/elasticsearch-7.12.0/plugins/ik
2)重启es服务
#查看端口服务PID
netstat -tunlp
# 杀死指定PID
kill -9 指定服务PID
3)测试查看中文分词效果
ik_smart , ik_max_word
# 查看分词效果
# ik_smart使用
GET /_analyze
{
"tokenizer": "ik_smart",
"text":"山东省青岛市"
}
# ik_max_word使用
GET /_analyze
{
"tokenizer": "ik_max_word",
"text":"山东省青岛市"
}
中文分词器的使用
测试用例:
# 创建索引名为test6以及属性数据格式
PUT /test6
{
"mappings": {
"properties": {
"name":{
"type":"text"
},
"age":{
"type": "byte"
},
"addr":{
"type":"text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
}
}
# 创建test6索引添加数据
POST /_bulk
{"index":{"_index":"test6","_id":1}}
{"name":"user1","age":35,"addr":"山东省青岛市"}
{"index":{"_index":"test6","_id":2}}
{"name":"user2","age":36,"addr":"山东省枣庄市"}
{"index":{"_index":"test6","_id":3}}
{"name":"user3","age":20,"addr":"江苏省南京市"}
{"index":{"_index":"test6","_id":4}}
{"name":"user4","age":23,"addr":"江苏省苏州市"}
{"index":{"_index":"test6","_id":5}}
{"name":"user5","age":20,"addr":"中国首都北京市"}
{"index":{"_index":"test6","_id":6}}
{"name":"user6","age":20,"addr":"hello world"}
{"index":{"_index":"test6","_id":7}}
{"name":"user7","age":51,"addr":"华为/HUAWEI nova 9 SE 一亿像素超清摄影 创新Vlog体验 支持66W快充"}
# 查询test6数据查看是否是中文分词查询
POST /test6/_search
{
"query": {
"match": {
"addr": "华为手机"
}
},
"highlight": {
"fields": {
"addr": {}
},
"tags_schema": "styled",
"pre_tags": [""],
"post_tags": [""]
}
}
自定义分词器使用(暂时不用,先搁置)