惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
Microsoft Azure Blog
Microsoft Azure Blog
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
Apple Machine Learning Research
Apple Machine Learning Research
O
OpenAI News
酷 壳 – CoolShell
酷 壳 – CoolShell
The GitHub Blog
The GitHub Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - 聂微东
Engineering at Meta
Engineering at Meta
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
大猫的无限游戏
大猫的无限游戏
Vercel News
Vercel News
D
Docker
F
Full Disclosure
AI
AI
罗磊的独立博客
博客园 - 【当耐特】
U
Unit 42
S
SegmentFault 最新的问题
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Palo Alto Networks Blog
博客园_首页
H
Help Net Security
量子位
月光博客
月光博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 司徒正美
F
Fortinet All Blogs
D
DataBreaches.Net
B
Blog RSS Feed
Webroot Blog
Webroot Blog
TaoSecurity Blog
TaoSecurity Blog
S
Secure Thoughts
爱范儿
爱范儿
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Attack and Defense Labs
Attack and Defense Labs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
C
CERT Recently Published Vulnerability Notes
Martin Fowler
Martin Fowler
Blog — PlanetScale
Blog — PlanetScale
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Securelist

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例) 读《为什么学生不喜欢上学》 OpenAI Prompt Engineering 摘录和总结 读《打造真正的新产品》 VueJS 总结 Linux 自动挂载 alist 提供的webdav FreeBSD 使用 vm-bhyve 安装Debian虚拟机 FreeBSD 和 Linux 网卡聚合实现提速 GPT 帮我搞定了时区转换问题 长任务系统如何处理? macOS/Linux 编译 InputLeap 使用开源软KVM - synergy-core 解决 macOS 终端hostname一直变化问题 KVM 共享 Intel 集成显卡 PromQL 备忘 读《格鲁夫给经理人的第一课》 读《打开心智》 为什么要把复杂的联表操作拆成多个单表查询? 红包系统的设计 MySQL Index Condition Pushdown Optimization Go mod 简明教程 OpenWRT 使用 Android/iOS USB 网络 搭建旁路由 Golang gRPC 错误处理 编写可维护的单元测试代码 OAuth 2 详解(六):Authorization Code Flow with PKCE OAuth 2 详解(五):Device Authorization Flow OAuth 2 详解(三):Resource Owner Password Credentials Grant OAuth 2 详解(四):Client Credentials Flow OAuth 2 详解(二):Implict Grant Flow OAuth 2 详解(一):简介及 Authorization Code 模式 三种git流程以及发版模型 错误处理实践 权限模型(RBAC/ABAC) OIDC(OpenID Connect) 简介 任务队列简介 PostgreSQL 操作笔记 使用Drone CI构建CI/CD系统 Golang migrate 做数据库变更管理 使用PostgreSQL做搜索引擎 Nginx 源码阅读(三): 连接池、内存池 Nginx 源码阅读(二): 请求处理 Nginx 源码阅读(一): 启动流程 Go 泛型简明教程 KVM 显卡穿透给 Windows 使用 HTTP Router 处理 Telegram Bot 按钮回调 使用反射(reflect)对结构体赋值 GIN 是如何绑定参数的 你好 2022(2021 年终总结) 用Go导入大型CSV到PostgreSQL 使用 OpenWRT 搭建软路由 使用软KVM切换器 barrier 共享键鼠 SQL 防注入及原理 使用 gomock 测试 Go 代码 gevent不是黑魔法(二): gevent 实现 gevent不是黑魔法(一): greenlet 实现 用 entgo 替代 gorm 应用内使用crontab不是那么方便 单测时要不要 mock 数据库? Sentry 自建指南 用selenium完成自动化任务 用闲置的安卓手机做垃圾电话短信过滤 推荐三个时间管理工具 一次事故反思 当JS遇到uint64:JS整数溢出问题 SQLite3 存储以及ACID原理 Redis源码阅读:pub/sub实现 Redis源码阅读:zset实现 Redis源码阅读:bitmap 位图的运算 Redis源码阅读:set是怎么做交并集运算的? Redis源码阅读:list实现(ziplist, quicklist)
ElasticSearch 学习笔记
Jiajun Huang · 2022-10-06 · via Jiajun的技术笔记

最近在学习使用ES,这篇博客记录一下相关的知识。在此之前,我都是使用PG的全文索引 来做搜索。

ES和PG一样,自带的插件对于中文的支持都不能用,之前使用PG做全文索引,是在应用内 进行分词,而ES则是使用ik插件。

安装

ES 是Java写的,可以直接安装在机器上,我选择通过Docker安装:

$ docker run --restart=always -d --name elasticsearch -p 9200:9200 -p 9300:9300 \
    -e "xpack.security.enabled=true" \
    -e "xpack.security.http.ssl.enabled=false" \
    -e "xpack.security.transport.ssl.enabled=false" \
    -e ELASTIC_USERNAME=elastic \
    -e ELASTIC_PASSWORD=<密码> \
    -e "discovery.type=single-node" \
    -v <PATH TO DATA>:/usr/share/elasticsearch/data/ \
    -v <PATH TO PLUGIN>:/usr/share/elasticsearch/plugins \
    elasticsearch:8.4.1

这样安装比较方便,注意要把 <PATH TO DATA><PATH TO PLUGIN> 替换成本地目录, <密码> 换成自定义密码。这两个目录用于保存数据和插件。这样,我们就可以开始使用单节点的ES了。

基本概念

ES 有几个基本概念我们需要了解,如果你使用过其它数据库,那么就很容易理解了:

  • Index: 一个索引,就是一堆 Documents 的集合。可以理解为关系型数据库里的 database,MongoDB 里的 collection
  • Mapping: 每个索引,都会有多个字段,而 Mapping 就是索引的结构。可以类比为关系型数据库里的 Schema
  • Documents: 一个文档,就是ES中被索引的基础信息单元,在ES里是一个JSON。可以类比为 MongoDB 里的 Document

理解了这三个概念,就可以开始使用ES了。我们再来复习一遍:

每一个Document,是ES中可以被索引的最小单元,其实就是一个JSON。多个Documents组成 一个Index。虽然我们使用时,可以不告诉ES Document中有什么字段是什么类型,但是Index 其实是需要这些信息的,我们不提供时,ES会自己猜测类型。而这个Document结构,就是 Mapping。

集成kibana

为了方便使用,我们再起一个Kibana。Kibana是一个管理ES数据的图形界面,准确来说是一个 Web服务。为了让Kibana能连接上ES,我们得为Kibana创建一个 service account

$ http POST http://elastic:密码@127.0.0.1:9200/_security/service/elastic/kibana/credential/token/kibana

接着用上一步返回的token,启动kibana:

$ docker run --restart=always -d --name kibana --network=host -p 5601:5601 \
    -e ELASTICSEARCH_HOSTS='http://127.0.0.1:9200' \
    -e ELASTICSEARCH_SERVICEACCOUNTTOKEN='<上一步生成的token>' \
    docker.elastic.co/kibana/kibana:8.4.1

接着,我们就可以打开Kibana,输入ES的用户名密码登录,接着在左侧导航栏,找到 Dev Tools, 接着我们就可以开始操作了。

安装中文分词插件

在真正开始索引数据之前,我们需要安装一下插件:

$ docker exec -it elasticsearch bash
$ elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.4.1/elasticsearch-analysis-ik-8.4.1.zip

注意,如果你的版本不是 8.4.1,那么需要更换成你的版本。安装完之后,重启ES。

索引与检索

创建索引

首先第一步,我们需要创建一个Index。在我们不指定Index结构的情况下,ES会根据输入的JSON自己猜测结构。但是实际上,ES猜测出来的 结构未必是我们想要的,生产上一般不这么干。我们一般会自己指定结构,在 Dev Tools 中输入如下内容,然后点击右上角的绿色三角形,就会执行:

PUT /words
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "age": {
        "type": "integer",
        "index": false
     }
    }
  }
}

可以看到右侧返回信息:

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "words"
}

说明索引成功创建。这个索引中,我们创建了两个字段:

  • content 类型为 text,写入时使用 ik_max_word 做分词,搜索时使用 ik_smart 分词。这两个的区别在于,前者产生尽可能多的分词,后者产生粗粒度的分词。
  • age 类型为 integerindex: false 表示不做索引。

文档参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html

更改索引

ES中,只能增加删除字段,不能更改已有字段的类型,所以要求我们创建的时候,就确定好类型:

PUT /words/_mapping
{
  "properties": {
    "content": {
      "type": "keyword"
    }
  }
}

返回报错:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "mapper [content] cannot be changed from type [text] to [keyword]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "mapper [content] cannot be changed from type [text] to [keyword]"
  },
  "status": 400
}

但是我们可以增加字段:

PUT /words/_mapping
{
  "properties": {
    "name": {
      "type": "keyword"
    }
  }
}

返回成功:

{
  "acknowledged": true
}

文档参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html

获取索引信息

GET /words  # 获取索引的信息
GET /words/_mapping  # 获取索引结构信息
GET /words/_settings  # 获取索引相关设置信息

文档参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-get-index.html

索引一个文档

POST /words/_doc/1
{
  "content": "你好世界世界你好",
  "age": 10,
  "name": "测试1"
}

返回成功:

{
  "_index": "words",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

ES 的行为是:如果没有就创建,有的话,就更新。如果不填 _id,也就是 _doc/1 中的1这一段,那么ES就会自动生成一个 Docuemtn ID。

文档参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html

加快索引的速度

如果大量导入文件,为了提高索引速度,我们可以做的事情有:

  • 批量导入,使用 _bulk 接口
  • 客户端多线程导入,提高请求并发量
  • 调大文档刷新间隔,默认情况下,ES每1秒刷新一次文档,让新索引进来的文档可以被搜索到,但是这样会降低索引速度。可以这样操作:

    PUT /words/_settings
    {
    "index.refresh_interval": "10m"
    }
    

将刷新间隔设置为10分钟。

  • 写入时,如果是集群,可以将replicas设置为1,避免多次写入
  • 禁用所在机器的swap
  • 加大文件系统的缓存
  • 不指定ID,让ES自动生成。这一点,需要结合实际业务需求来做
  • 加硬件!更好的硬件当然更快
  • 调大 indices.memory.index_buffer_size
  • 使用多节点,避免大量创建索引时导致搜索卡住
  • 不需要索引的字段不索引
  • 显示指定Mapping,不要让ES猜测。ES猜测出来的类型,通常不是我们想要的,它会同时创建为 textkeyword 两种,比较浪费磁盘
  • 每个 shard 不要过大
  • 禁用 _source。不过我一般是留着。_source 保存了原始输入的JSON
  • 考虑启用 best_compression,可以节省磁盘,但是会更费CPU
  • 采用可以表示的最小类型,比如如果 integer 可以表示,就不要用 long,因为他们占用的字节数不一样
  • 定期归档旧数据

文档参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-indexing-speed.htmlhttps://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-disk-usage.html

数据类型

最后,我们来看看ES的常用数据类型:

  • binary 二进制数据,encode成base64保存
  • boolean true或者false
  • keywordtext 差不多,但是不会分词,必须精确匹配才能搜索到
  • numbers 分为 integer, long, double 等,表示具体数据类型
  • date 存储日期
  • alias 为已有字段创建别名
  • ip 存储IP地址
  • text 存储文本,会进行分词

其余类型,参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html

总结

ES无疑是强大的,但是它也有缺点,那就是很吃硬件,像2C4G的机器,跑ES本身就已经很吃力,更别提批量导入数据的时候了。这里我们 记录了ES的一些基本知识,业内,ES通常是使用ELK全家桶,用来存储和搜索日志。当然,如果有搜索需求的话,也会使用ES做搜索。 除此之外,elastic 还在探索把ES作为APM的数据存储系统,但是目前看来还没有完全推广开来。

ES目前已经和其它数据库一样,成为程序员必须掌握的一个工具,希望这篇文章能够给你带来一定的帮助。


ref: