Elasticsearch是什么
Elasticsearch 是一个基于 Apache Lucene 构建的分布式搜索和分析引擎、可扩展的数据存储和矢量数据库。 它针对生产规模工作负载的速度和相关性进行了优化。 使用 Elasticsearch 近乎实时地搜索、索引、存储和分析各种形状和大小的数据。
特点
-
分布式:Elasticsearch 设计为在多台服务器上运行,可以处理大量数据和高并发请求。
-
高可扩展性:可以轻松地通过增加更多的节点来扩展集群,以提高搜索和索引的性能。
-
实时搜索:Elasticsearch 能够提供接近实时的搜索体验,这意味着在索引数据后,可以立即搜索到这些数据。
-
多租户:支持多租户架构,允许多个用户或应用程序共享同一个 Elasticsearch 集群。
-
RESTful API:Elasticsearch 提供了一个基于 REST 的 API,使得与搜索引擎的交互变得简单,可以通过 HTTP 请求来索引、搜索、更新和删除数据。
-
JSON 文档:Elasticsearch 使用 JSON 格式来存储和索引数据,这使得它易于与其他使用 JSON 的应用程序集成。
-
分析和聚合:Elasticsearch 提供了强大的分析和聚合功能,可以对数据进行复杂的分析,如计算平均值、总和、计数等。
-
索引和搜索功能:Elasticsearch 提供了丰富的索引和搜索功能,包括全文搜索、精确匹配、范围查询、模糊搜索等。
-
监控和日志:Elasticsearch 通常与其他 Elastic Stack 产品(如 Logstash 和 Kibana)一起使用,用于监控、日志记录和可视化数据。
-
安全性:Elasticsearch 提供了安全特性,如用户认证、授权和加密,以保护数据和集群的安全。
Elasticsearch 广泛应用于日志分析、全文搜索、安全情报、业务分析等领域。它的灵活性和可扩展性使其成为处理大规模搜索和分析任务的理想选择。
Elasticsearch核心概念
1、Cluster:集群
Elasticsearch可以作为一个独立的单个搜索服务器,不过,为了处理大型数据集,实现容错和高可用性,Elasticsearch可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。
2、Node:节点
形成集群的每个服务器称为节点。
3、Shard:分片
当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。这种情况下,数据可以分为较小的分片。每个分片放到不同的服务器上。 当你查询的索引分布在多个分片上时,Elasticsearch会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。即:这个过程对用户来说是透明的。
4、Replia:副本
为提高查询吞吐量或实现高可用性,可以使用分片副本。 副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。 当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片。
索引结构
下图是索引结构,下边黑色部分是物理结构,上边蓝色部分是逻辑结构,逻辑结构也是为了更好的去描述工作原理及去使用物理结构中的索引文件。
Elasticsearch工作原理
当Elasticsearch的节点启动后,它会利用多播(multicast)(或者单播,如果用户更改了配置)寻找集群中的其它节点,并与之建立连接。
Elasticsearch数据架构的主要概念(与关系数据库Mysql对比)
安装
- 前提条件:需要jdk,超详细JDK下载与安装步骤(保姆级,含安装包)
- 要想安装 Elasticsearch,先下载并解压适合你操作系统的 Elasticsearch 版本: Elasticsearch官网
例如:windows下载
- 解压之后进入bin目录下,双击执行elasticsearch.bat
4.看到started说明启动成功,打开浏览器访问:http://localhost:9200/
页面化工具Kibana安装
Kibana官网:Kibana 的版本需要和 Elasticsearch 的版本一致
安装前提
ElasticSearch安装
Node.js安装:Windows下安装及配置Node.js
下载安装
在 Windows 中安装 Kibana 使用 .zip
包
配置
在编辑器中打开config / kibana.yml
设置elasticsearch.url
为指向您的Elasticsearch实例
默认值: "http://localhost:9200" 用来处理所有查询的 Elasticsearch 实例的 URL
运行
双击 bin\kibana.bat,浏览器访问:
http://localhost:5601/
使用示例
连接
Go
import (
"es_study/global"
"fmt"
"github.com/olivere/elastic/v7"
)
func EsConnect() {
client, err := elastic.NewClient(
elastic.SetURL("http://127.0.0.1:9200"),
elastic.SetSniff(false),
elastic.SetBasicAuth("", ""),
)
if err != nil {
fmt.Println(err)
return
}
global.ESClient = client
}
mapping映射
Go
{
"mappings": {
"properties": {
"title": {
"type": "text" // 查询的时候是分词匹配
},
"key": {
"type": "keyword" // 完整匹配
},
"user_id": {
"type": "integer"
},
"created_at":{
"type": "date",
"null_value": "null",
"format": "[yyyy-MM-dd HH:mm:ss]"
}
}
}
}
创建索引
-
判断索引是否存在,如果存在,删除索引
-
创建索引
Go
func CreateIndex() {
index := "user_index"
if ExistsIndex(index) {
// 索引存在,先删除,在创建
DeleteIndex(index)
}
createIndex, err := global.ESClient.
CreateIndex(index).
BodyString(models.UserModel{}.Mapping()).Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Println(createIndex.Index, "索引创建成功")
}
// ExistsIndex 判断索引是否存在
func ExistsIndex(index string) bool {
exists, _ := global.ESClient.IndexExists(index).Do(context.Background())
return exists
}
func DeleteIndex(index string) {
_, err := global.ESClient.
DeleteIndex(index).Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Println(index, "索引删除成功")
}
批量添加/删除
Go
//批量添加
func DocCreateBatch() {
list := []models.UserModel{
{
ID: 12,
UserName: "zs",
NickName: "张三",
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
},
{
ID: 13,
UserName: "ls",
NickName: "李四",
CreatedAt: time.Now().Format("2006-01-02 15:04:05"),
},
}
bulk := global.ESClient.Bulk().Index(models.UserModel{}.Index()).Refresh("true")
for _, model := range list {
req := elastic.NewBulkCreateRequest().Doc(model)
bulk.Add(req)
}
res, err := bulk.Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res.Succeeded())
}
//批量删除
func DocDeleteBatch() {
idList := []string{
"tGcofYkBWS69Op6QHJ2g",
"tWcpfYkBWS69Op6Q050w",
}
bulk := global.ESClient.Bulk().Index(models.UserModel{}.Index()).Refresh("true")
for _, s := range idList {
req := elastic.NewBulkDeleteRequest().Id(s)
bulk.Add(req)
}
res, err := bulk.Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res.Succeeded()) // 实际删除的文档切片
}
文档查询
Go
// 1、列表查询
func DocFind() {
limit := 2
page := 4
from := (page - 1) * limit
query := elastic.NewBoolQuery()
res, err := global.ESClient.Search(models.UserModel{}.Index()).Query(query).From(from).Size(limit).Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
count := res.Hits.TotalHits.Value // 总数
fmt.Println(count)
for _, hit := range res.Hits.Hits {
fmt.Println(string(hit.Source))
}
}
// 2、精准查询
query := elastic.NewTermQuery("user_name", "zs")
// 3、模糊查询
query := elastic.NewMatchQuery("nick_name", "张三")
// 4、嵌套字段查询
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
//因为title是text类型,只能模糊匹配,但是需要精确匹配的时候,也能通过title.keyword的形式进行精确匹配
query := elastic.NewTermQuery("title.keyword", "王五") // 精确匹配
query := elastic.NewMatchQuery("title", "王五") // 模糊匹配
文档更新
Go
func DocUpdate() {
res, err := global.ESClient.Update().Index(models.UserModel{}.Index()).
Id("vmdnfYkBWS69Op6QEp2Y").Doc(map[string]any{
"user_name": "你好呀",
}).Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%#v\n", res)
}