This commit is contained in:
周伟
2022-05-11 18:46:27 +08:00
commit 387f48277a
8634 changed files with 2579564 additions and 0 deletions

View File

@@ -0,0 +1,754 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>01 认知ElasticSearch基础概念.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>01 认知ElasticSearch基础概念</h1>
<h2>为什么需要学习ElasticSearch</h2>
<blockquote>
<p>根据<a href="https://db-engines.com/en/ranking">DB Engine的排名 </a>显示ElasticSearch是最受欢迎的企业级搜索引擎。</p>
</blockquote>
<p>下图红色勾选的是我们前面的系列详解的除此之外你可以看到搜索库ElasticSearch在前十名内</p>
<p><img src="assets/es-introduce-1-2.png" alt="img" /></p>
<p>所以为什么要学习ElasticSearch呢</p>
<p>1、在当前软件行业中搜索是一个软件系统或平台的基本功能 学习ElasticSearch就可以为相应的软件打造出良好的搜索体验。</p>
<p>2、其次ElasticSearch具备非常强的大数据分析能力。虽然Hadoop也可以做大数据分析但是ElasticSearch的分析能力非常高具备Hadoop不具备的能力。比如有时候用Hadoop分析一个结果可能等待的时间比较长。</p>
<p>3、ElasticSearch可以很方便的进行使用可以将其安装在个人的笔记本电脑也可以在生产环境中将其进行水平扩展。</p>
<p>4、国内比较大的互联网公司都在使用比如小米、滴滴、携程等公司。另外在腾讯云、阿里云的云平台上也都有相应的ElasticSearch云产品可以使用。</p>
<p>5、在当今大数据时代掌握近实时的搜索和分析能力才能掌握核心竞争力洞见未来。</p>
<h2>什么是ElasticSearch</h2>
<blockquote>
<p>ElasticSearch是一款非常强大的、基于Lucene的开源搜索及分析引擎它是一个实时的分布式搜索分析引擎它能让你以前所未有的速度和规模去探索你的数据。</p>
</blockquote>
<p>它被用作<strong>全文检索</strong><strong>结构化搜索</strong><strong>分析</strong>以及这三个功能的组合:</p>
<ul>
<li><em>Wikipedia</em> 使用 Elasticsearch 提供带有高亮片段的全文搜索,还有 search-as-you-type 和 did-you-mean 的建议。</li>
<li><em>卫报</em> 使用 Elasticsearch 将网络社交数据结合到访客日志中,为它的编辑们提供公众对于新文章的实时反馈。</li>
<li><em>Stack Overflow</em> 将地理位置查询融入全文检索中去,并且使用 more-like-this 接口去查找相关的问题和回答。</li>
<li><em>GitHub</em> 使用 Elasticsearch 对1300亿行代码进行查询。</li>
<li>...</li>
</ul>
<p>除了搜索结合Kibana、Logstash、Beats开源产品Elastic Stack简称ELK还被广泛运用在大数据近实时分析领域包括<strong>日志分析</strong><strong>指标监控</strong><strong>信息安全</strong>等。它可以帮助你<strong>探索海量结构化、非结构化数据,按需创建可视化报表,对监控数据设置报警阈值,通过使用机器学习,自动识别异常状况</strong></p>
<p>ElasticSearch是基于Restful WebApi使用Java语言开发的搜索引擎库类并作为Apache许可条款下的开放源码发布是当前流行的企业级搜索引擎。其客户端在Java、C#、PHP、Python等许多语言中都是可用的。</p>
<h3>ElasticSearch的由来</h3>
<blockquote>
<p>ElasticSearch背后的小故事</p>
</blockquote>
<p>许多年前,一个刚结婚的名叫 Shay Banon 的失业开发者,跟着他的妻子去了伦敦,他的妻子在那里学习厨师。 在寻找一个赚钱的工作的时候,为了给他的妻子做一个食谱搜索引擎,他开始使用 Lucene 的一个早期版本。</p>
<p>直接使用 Lucene 是很难的,因此 Shay 开始做一个抽象层Java 开发者使用它可以很简单的给他们的程序添加搜索功能。 他发布了他的第一个开源项目 Compass。</p>
<p>后来 Shay 获得了一份工作,主要是高性能,分布式环境下的内存数据网格。这个对于高性能,实时,分布式搜索引擎的需求尤为突出, 他决定重写 Compass把它变为一个独立的服务并取名 Elasticsearch。</p>
<p>第一个公开版本在2010年2月发布从此以后Elasticsearch 已经成为了 Github 上最活跃的项目之一他拥有超过300名 contributors(目前736名 contributors )。 一家公司已经开始围绕 Elasticsearch 提供商业服务并开发新的特性但是Elasticsearch 将永远开源并对所有人可用。</p>
<p>据说Shay 的妻子还在等着她的食谱搜索引擎…</p>
<h3>为什么不是直接使用Lucene</h3>
<blockquote>
<p>ElasticSearch是基于Lucene的那么为什么不是直接使用Lucene呢</p>
</blockquote>
<p>Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库。</p>
<p>但是 Lucene 仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是您可能需要获得信息检索学位才能了解其工作原理。Lucene 非常 复杂。</p>
<p>Elasticsearch 也是使用 Java 编写的,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单,<strong>通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API</strong></p>
<p>然而Elasticsearch 不仅仅是 Lucene并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:</p>
<ul>
<li>一个分布式的实时文档存储,每个字段 可以被索引与搜索</li>
<li>一个分布式实时分析搜索引擎</li>
<li>能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据</li>
</ul>
<h3>ElasticSearch的主要功能及应用场景</h3>
<blockquote>
<p>我们在哪些场景下可以使用ES呢</p>
</blockquote>
<ul>
<li>主要功能:</li>
</ul>
<p>1海量数据的分布式存储以及集群管理达到了服务与数据的高可用以及水平扩展</p>
<p>2近实时搜索性能卓越。对结构化、全文、地理位置等类型数据的处理</p>
<p>3海量数据的近实时分析聚合功能</p>
<ul>
<li>应用场景:</li>
</ul>
<p>1网站搜索、垂直搜索、代码搜索</p>
<p>2日志管理与分析、安全指标监控、应用性能监控、Web抓取舆情分析</p>
<h2>ElasticSearch的基础概念</h2>
<blockquote>
<p>我们还需对比结构化数据库看看ES的基础概念为我们后面学习作铺垫。</p>
</blockquote>
<ul>
<li><strong>Near RealtimeNRT</strong> 近实时。数据提交索引后,立马就可以搜索到。</li>
<li><strong>Cluster 集群</strong>一个集群由一个唯一的名字标识默认为“elasticsearch”。集群名称非常重要具有相同集群名的节点才会组成一个集群。集群名称可以在配置文件中指定。</li>
<li><strong>Node 节点</strong>存储集群的数据参与集群的索引和搜索功能。像集群有名字节点也有自己的名称默认在启动时会以一个随机的UUID的前七个字符作为节点的名字你可以为其指定任意的名字。通过集群名在网络中发现同伴组成集群。一个节点也可是集群。</li>
<li><strong>Index 索引</strong>: 一个索引是一个文档的集合等同于solr中的集合。每个索引有唯一的名字通过这个名字来操作它。一个集群中可以有任意多个索引。</li>
<li><strong>Type 类型</strong>指在一个索引中可以索引不同类型的文档如用户数据、博客数据。从6.0.0 版本起已废弃,一个索引中只存放一类数据。</li>
<li><strong>Document 文档</strong>被索引的一条数据索引的基本信息单元以JSON格式来表示。</li>
<li><strong>Shard 分片</strong>:在创建一个索引时可以指定分成多少个分片来存储。每个分片本身也是一个功能完善且独立的“索引”,可以被放置在集群的任意节点上。</li>
<li><strong>Replication 备份</strong>: 一个分片可以有多个备份(副本)</li>
</ul>
<p>为了方便理解作一个ES和数据库的对比</p>
<p><img src="assets/es-introduce-1-3.png" alt="img" /></p>
<h2>参考文章</h2>
<ul>
<li>https://www.elastic.co/guide/cn/elasticsearch/guide/current/intro.html</li>
<li>https://www.elastic.co/guide/cn/elasticsearch/guide/current/getting-started.html</li>
<li>https://www.cnblogs.com/leeSmall/p/9189078.html</li>
</ul>
</div>
</div>
<div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996f8cde0f3d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,764 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>02 认知Elastic Stack生态和场景方案.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>02 认知Elastic Stack生态和场景方案</h1>
<h2>Elastic Stack生态</h2>
<blockquote>
<p>Beats + Logstash + ElasticSearch + Kibana</p>
</blockquote>
<p>如下是我从官方博客中找到图这张图展示了ELK生态以及基于ELK的场景最上方</p>
<p><img src="assets/es-introduce-1-1.png" alt="img" /></p>
<p>由于Elastic X-Pack是面向收费的所以我们不妨也把X-Pack放进去看看哪些是由X-Pack带来的在阅读官网文档时将方便你甄别重点</p>
<p><img src="assets/es-introduce-1-0.png" alt="img" /></p>
<h3>Beats</h3>
<p>Beats是一个面向<strong>轻量型采集器</strong>的平台这些采集器可以从边缘机器向Logstash、ElasticSearch发送数据它是由Go语言进行开发的运行效率方面比较快。从下图中可以看出不同Beats的套件是针对不同的数据源。</p>
<p><img src="assets/es-introduce-2-0.png" alt="img" /></p>
<h3>Logstash</h3>
<p>Logstash是<strong>动态数据收集管道</strong>拥有可扩展的插件生态系统支持从不同来源采集数据转换数据并将数据发送到不同的存储库中。其能够与ElasticSearch产生强大的协同作用后被Elastic公司在2013年收购。</p>
<p>它具有如下特性:</p>
<p>1实时解析和转换数据</p>
<p>2可扩展具有200多个插件</p>
<p>3可靠性、安全性。Logstash会通过持久化队列来保证至少将运行中的事件送达一次同时将数据进行传输加密</p>
<p>4监控</p>
<h3>ElasticSearch</h3>
<p>ElasticSearch对数据进行<strong>搜索、分析和存储</strong>其是基于JSON的分布式搜索和分析引擎专门为实现水平可扩展性、高可靠性和管理便捷性而设计的。</p>
<p>它的实现原理主要分为以下几个步骤:</p>
<p>1首先用户将数据提交到ElasticSearch数据库中</p>
<p>2再通过分词控制器将对应的语句分词</p>
<p>3将分词结果及其权重一并存入以备用户在搜索数据时根据权重将结果排名和打分将返回结果呈现给用户</p>
<h3>Kibana</h3>
<p>Kibana实现<strong>数据可视化</strong>其作用就是在ElasticSearch中进行民航。Kibana能够以图表的形式呈现数据并且具有可扩展的用户界面可以全方位的配置和管理ElasticSearch。</p>
<p>Kibana最早的时候是基于Logstash创建的工具后被Elastic公司在2013年收购。</p>
<p>1Kibana可以提供各种可视化的图表</p>
<p>2可以通过机器学习的技术对异常情况进行检测用于提前发现可疑问题</p>
<h2>从日志收集系统看ES Stack的发展</h2>
<blockquote>
<p>我们看下ELK技术栈的演化通常体现在日志收集系统中。</p>
</blockquote>
<p>一个典型的日志系统包括:</p>
<p>1收集能够采集多种来源的日志数据</p>
<p>2传输能够稳定的把日志数据解析过滤并传输到存储系统</p>
<p>3存储存储日志数据</p>
<p>4分析支持 UI 分析</p>
<p>5警告能够提供错误报告监控机制</p>
<h3>beats+elasticsearch+kibana</h3>
<p>Beats采集数据后存储在ES中有Kibana可视化的展示。</p>
<p><img src="assets/es-introduce-2-1.png" alt="img" /></p>
<h3>beats+logstath+elasticsearch+kibana</h3>
<p><img src="assets/es-introduce-2-2.png" alt="img" /></p>
<p>该框架是在上面的框架的基础上引入了logstash引入logstash带来的好处如下</p>
<p>1Logstash具有基于磁盘的自适应缓冲系统该系统将吸收传入的吞吐量从而减轻背压。</p>
<p>2从其他数据源例如数据库S3或消息传递队列中提取。</p>
<p>3将数据发送到多个目的地例如S3HDFS或写入文件。</p>
<p>4使用条件数据流逻辑组成更复杂的处理管道。</p>
<p><strong>beats结合logstash带来的优势</strong></p>
<p>1水平可扩展性高可用性和可变负载处理beats和logstash可以实现节点之间的负载均衡多个logstash可以实现logstash的高可用</p>
<p>2消息持久性与至少一次交付保证使用beats或Winlogbeat进行日志收集时可以保证至少一次交付。从Filebeat或Winlogbeat到Logstash以及从Logstash到Elasticsearch的两种通信协议都是同步的并且支持确认。Logstash持久队列提供跨节点故障的保护。对于Logstash中的磁盘级弹性确保磁盘冗余非常重要。</p>
<p>3具有身份验证和有线加密的端到端安全传输从Beats到Logstash以及从 Logstash到Elasticsearch的传输都可以使用加密方式传递 。与Elasticsearch进行通讯时有很多安全选项包括基本身份验证TLSPKILDAPAD和其他自定义领域</p>
<p><strong>增加更多的数据源</strong> 比如TCPUDP和HTTP协议是将数据输入Logstash的常用方法</p>
<p><img src="assets/es-introduce-2-3.png" alt="img" /></p>
<h3>beats+MQ+logstash+elasticsearch+kibana</h3>
<p><img src="assets/es-introduce-2-4.png" alt="img" /></p>
<p>在如上的基础上我们可以在beats和logstash中间添加一些组件redis、kafka、RabbitMQ等添加中间件将会有如下好处</p>
<p>1降低对日志所在机器的影响这些机器上一般都部署着反向代理或应用服务本身负载就很重了所以尽可能的在这些机器上少做事</p>
<p>2如果有很多台机器需要做日志收集那么让每台机器都向Elasticsearch持续写入数据必然会对Elasticsearch造成压力因此需要对数据进行缓冲同时这样的缓冲也可以一定程度的保护数据不丢失</p>
<p>3将日志数据的格式化与处理放到Indexer中统一做可以在一处修改代码、部署避免需要到多台机器上去修改配置</p>
<h2>Elastic Stack最佳实践</h2>
<blockquote>
<p>我们再看下官方开发成员分享的最佳实践。</p>
</blockquote>
<h3>日志收集系统</h3>
<p>PS就是我们上面阐述的</p>
<p>基本的日志系统</p>
<p><img src="assets/es-introduce-2-5.png" alt="img" /></p>
<p>增加数据源和使用MQ</p>
<p><img src="assets/es-introduce-2-6.png" alt="img" /></p>
<h3>Metric收集和APM性能监控</h3>
<p><img src="assets/es-introduce-2-7.png" alt="img" /></p>
<h3>多数据中心方案</h3>
<p>通过冗余实现数据高可用</p>
<p><img src="assets/es-introduce-2-8.png" alt="img" /></p>
<p>两个数据采集中心(比如采集两个工厂的数据),采集数据后的汇聚</p>
<p><img src="assets/es-introduce-2-9.png" alt="img" /></p>
<p>数据分散,跨集群的搜索</p>
<p><img src="assets/es-introduce-2-10.png" alt="img" /></p>
<h2>参考文章</h2>
<ul>
<li>https://www.elastic.co/cn/elasticsearch/</li>
<li>https://www.elastic.co/pdf/architecture-best-practices.pdf</li>
<li>https://www.elastic.co/guide/en/logstash/current/deploying-and-scaling.html</li>
<li>https://www.cnblogs.com/supersnowyao/p/11110703.html</li>
<li>https://blog.51cto.com/wutengfei/2645627</li>
</ul>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996f8f1ad83d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,946 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>05 索引:索引管理详解.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>05 索引:索引管理详解</h1>
<h2>索引管理的引入</h2>
<p>我们在前文中增加文档时如下的语句会动态创建一个customer的index</p>
<pre><code class="language-bash">PUT /customer/_doc/1
{
&quot;name&quot;: &quot;John Doe&quot;
}
</code></pre>
<p>而这个index实际上已经自动创建了它里面的字段name的类型。我们不妨看下它自动创建的mapping</p>
<pre><code class="language-json">{
&quot;mappings&quot;: {
&quot;_doc&quot;: {
&quot;properties&quot;: {
&quot;name&quot;: {
&quot;type&quot;: &quot;text&quot;,
&quot;fields&quot;: {
&quot;keyword&quot;: {
&quot;type&quot;: &quot;keyword&quot;,
&quot;ignore_above&quot;: 256
}
}
}
}
}
}
}
</code></pre>
<p>那么如果我们需要对这个建立索引的过程做更多的控制:比如想要确保这个索引有数量适中的主分片,并且在我们索引任何数据之前,分析器和映射已经被建立好。那么就会引入两点:第一个<strong>禁止自动创建索引</strong>,第二个是<strong>手动创建索引</strong></p>
<ul>
<li>禁止自动创建索引</li>
</ul>
<p>可以通过在 config/elasticsearch.yml 的每个节点下添加下面的配置:</p>
<pre><code class="language-bash">action.auto_create_index: false
</code></pre>
<p>手动创建索引就是接下来文章的内容。</p>
<h2>索引的格式</h2>
<p>在请求体里面传入设置或类型映射,如下所示:</p>
<pre><code class="language-bash">PUT /my_index
{
&quot;settings&quot;: { ... any settings ... },
&quot;mappings&quot;: {
&quot;properties&quot;: { ... any properties ... }
}
}
</code></pre>
<ul>
<li>
<p><strong>settings</strong>: 用来设置分片,副本等配置信息</p>
</li>
<li>
<p>mappings</p>
<p>: 字段映射,类型等</p>
<ul>
<li><strong>properties</strong>: 由于type在后续版本中会被Deprecated, 所以无需被type嵌套</li>
</ul>
</li>
</ul>
<h2>索引管理操作</h2>
<blockquote>
<p>我们通过kibana的devtool来学习索引的管理操作。</p>
</blockquote>
<h3>创建索引</h3>
<p>我们创建一个user 索引<code>test-index-users</code>其中包含三个属性nameage, remarks; 存储在一个分片一个副本上。</p>
<pre><code class="language-bash">PUT /test-index-users
{
&quot;settings&quot;: {
&quot;number_of_shards&quot;: 1,
&quot;number_of_replicas&quot;: 1
},
&quot;mappings&quot;: {
&quot;properties&quot;: {
&quot;name&quot;: {
&quot;type&quot;: &quot;text&quot;,
&quot;fields&quot;: {
&quot;keyword&quot;: {
&quot;type&quot;: &quot;keyword&quot;,
&quot;ignore_above&quot;: 256
}
}
},
&quot;age&quot;: {
&quot;type&quot;: &quot;long&quot;
},
&quot;remarks&quot;: {
&quot;type&quot;: &quot;text&quot;
}
}
}
}
</code></pre>
<p>执行结果</p>
<p><img src="assets/es-index-manage-1.png" alt="img" /></p>
<ul>
<li><strong>插入测试数据</strong></li>
</ul>
<p><img src="assets/es-index-manage-2.png" alt="img" /></p>
<p>查看数据</p>
<p><img src="assets/es-index-manage-3.png" alt="img" /></p>
<ul>
<li>我们再<strong>测试下不匹配的数据类型</strong>(age)</li>
</ul>
<pre><code class="language-bash">POST /test-index-users/_doc
{
&quot;name&quot;: &quot;test user&quot;,
&quot;age&quot;: &quot;error_age&quot;,
&quot;remarks&quot;: &quot;hello eeee&quot;
}
</code></pre>
<p>你可以看到无法类型不匹配的错误:</p>
<p><img src="assets/es-index-manage-4.png" alt="img" /></p>
<h3>修改索引</h3>
<p>查看刚才的索引,<code>curl 'localhost:9200/_cat/indices?v' | grep users</code></p>
<pre><code class="language-bash">yellow open test-index-users LSaIB57XSC6uVtGQHoPYxQ 1 1 1 0 4.4kb 4.4kb
</code></pre>
<p>我们注意到刚创建的索引的状态是yellow的因为我测试的环境是单点环境无法创建副本但是在上述<code>number_of_replicas</code>配置中设置了副本数是1 所以在这个时候我们需要修改索引的配置。</p>
<p>修改副本数量为0</p>
<pre><code class="language-bash">PUT /test-index-users/_settings
{
&quot;settings&quot;: {
&quot;number_of_replicas&quot;: 0
}
}
</code></pre>
<p><img src="assets/es-index-manage-5.png" alt="img" /></p>
<p>再次查看状态:</p>
<pre><code class="language-bash">green open test-index-users LSaIB57XSC6uVtGQHoPYxQ 1 1 1 0 4.4kb 4.4kb
</code></pre>
<h3>打开/关闭索引</h3>
<ul>
<li><strong>关闭索引</strong></li>
</ul>
<p>一旦索引被关闭,那么这个索引只能显示元数据信息,<strong>不能够进行读写操作</strong></p>
<p><img src="assets/es-index-manage-7.png" alt="img" /></p>
<p>当关闭以后,再插入数据时:</p>
<p><img src="assets/es-index-manage-8.png" alt="img" /></p>
<ul>
<li><strong>打开索引</strong></li>
</ul>
<p><img src="assets/es-index-manage-9.png" alt="img" /></p>
<p>打开后又可以重新写数据了</p>
<p><img src="assets/es-index-manage-10.png" alt="img" /></p>
<h3>删除索引</h3>
<p>最后我们将创建的test-index-users删除。</p>
<pre><code class="language-bash">DELETE /test-index-users
</code></pre>
<p><img src="assets/es-index-manage-11.png" alt="img" /></p>
<h3>查看索引</h3>
<p>由于test-index-users被删除所以我们看下之前bank的索引的信息</p>
<ul>
<li><strong>mapping</strong></li>
</ul>
<pre><code class="language-bash">GET /bank/_mapping
</code></pre>
<p><img src="assets/es-index-manage-12.png" alt="img" /></p>
<ul>
<li><strong>settings</strong></li>
</ul>
<pre><code class="language-bash">GET /bank/_settings
</code></pre>
<p><img src="assets/es-index-manage-13.png" alt="img" /></p>
<h2>Kibana管理索引</h2>
<p>在Kibana如下路径我们可以查看和管理索引</p>
<p><img src="assets/es-index-manage-6.png" alt="img" /></p>
<h2>参考文章</h2>
<p>https://www.elastic.co/guide/cn/elasticsearch/guide/current/_creating_an_index.html</p>
<p>https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html</p>
<p>https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html</p>
<p>https://www.cnblogs.com/quanxiaoha/p/11515057.html</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996f95fa563d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,946 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>09 查询DSL查询之Term详解.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>09 查询DSL查询之Term详解</h1>
<h2>Term查询引入</h2>
<p>如前文所述,查询分基于文本查询和基于词项的查询:</p>
<p><img src="assets/es-dsl-full-text-3.png" alt="img" /></p>
<p>本文主要讲基于词项的查询。</p>
<p><img src="assets/es-dsl-term-1.png" alt="img" /></p>
<h2>Term查询</h2>
<blockquote>
<p>很多比较常用,也不难,就是需要结合实例理解。这里综合官方文档的内容,我设计一个测试场景的数据,以覆盖所有例子。@pdai</p>
</blockquote>
<p>准备数据</p>
<pre><code class="language-bash">PUT /test-dsl-term-level
{
&quot;mappings&quot;: {
&quot;properties&quot;: {
&quot;name&quot;: {
&quot;type&quot;: &quot;keyword&quot;
},
&quot;programming_languages&quot;: {
&quot;type&quot;: &quot;keyword&quot;
},
&quot;required_matches&quot;: {
&quot;type&quot;: &quot;long&quot;
}
}
}
}
POST /test-dsl-term-level/_bulk
{ &quot;index&quot;: { &quot;_id&quot;: 1 }}
{&quot;name&quot;: &quot;Jane Smith&quot;, &quot;programming_languages&quot;: [ &quot;c++&quot;, &quot;java&quot; ], &quot;required_matches&quot;: 2}
{ &quot;index&quot;: { &quot;_id&quot;: 2 }}
{&quot;name&quot;: &quot;Jason Response&quot;, &quot;programming_languages&quot;: [ &quot;java&quot;, &quot;php&quot; ], &quot;required_matches&quot;: 2}
{ &quot;index&quot;: { &quot;_id&quot;: 3 }}
{&quot;name&quot;: &quot;Dave Pdai&quot;, &quot;programming_languages&quot;: [ &quot;java&quot;, &quot;c++&quot;, &quot;php&quot; ], &quot;required_matches&quot;: 3, &quot;remarks&quot;: &quot;hello world&quot;}
</code></pre>
<h3>字段是否存在:exist</h3>
<p>由于多种原因,文档字段的索引值可能不存在:</p>
<ul>
<li>源JSON中的字段是null或[]</li>
<li>该字段已&quot;index&quot; : false在映射中设置</li>
<li>字段值的长度超出ignore_above了映射中的设置</li>
<li>字段值格式错误并且ignore_malformed已在映射中定义</li>
</ul>
<p>所以exist表示查找是否存在字段。</p>
<p><img src="assets/es-dsl-term-2.png" alt="img" /></p>
<h3>id查询:ids</h3>
<p>ids 即对id查找</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;ids&quot;: {
&quot;values&quot;: [3, 1]
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-3.png" alt="img" /></p>
<h3>前缀:prefix</h3>
<p>通过前缀查找某个字段</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;prefix&quot;: {
&quot;name&quot;: {
&quot;value&quot;: &quot;Jan&quot;
}
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-4.png" alt="img" /></p>
<h3>分词匹配:term</h3>
<p>前文最常见的根据分词查询</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;term&quot;: {
&quot;programming_languages&quot;: &quot;php&quot;
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-5.png" alt="img" /></p>
<h3>多个分词匹配:terms</h3>
<p>按照读个分词term匹配它们是or的关系</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;terms&quot;: {
&quot;programming_languages&quot;: [&quot;php&quot;,&quot;c++&quot;]
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-6.png" alt="img" /></p>
<h3>按某个数字字段分词匹配:term set</h3>
<p>设计这种方式查询的初衷是用文档中的数字字段动态匹配查询满足term的个数</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;terms_set&quot;: {
&quot;programming_languages&quot;: {
&quot;terms&quot;: [ &quot;java&quot;, &quot;php&quot; ],
&quot;minimum_should_match_field&quot;: &quot;required_matches&quot;
}
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-7.png" alt="img" /></p>
<h3>通配符:wildcard</h3>
<p>通配符匹配,比如<code>*</code></p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;wildcard&quot;: {
&quot;name&quot;: {
&quot;value&quot;: &quot;D*ai&quot;,
&quot;boost&quot;: 1.0,
&quot;rewrite&quot;: &quot;constant_score&quot;
}
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-8.png" alt="img" /></p>
<h3>范围:range</h3>
<p>常常被用在数字或者日期范围的查询</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;range&quot;: {
&quot;required_matches&quot;: {
&quot;gte&quot;: 3,
&quot;lte&quot;: 4
}
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-9.png" alt="img" /></p>
<h3>正则:regexp</h3>
<p>通过[正则表达式]查询</p>
<p>&quot;Jan&quot;开头的name字段</p>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;regexp&quot;: {
&quot;name&quot;: {
&quot;value&quot;: &quot;Ja.*&quot;,
&quot;case_insensitive&quot;: true
}
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-10.png" alt="img" /></p>
<h3>模糊匹配:fuzzy</h3>
<p>官方文档对模糊匹配:编辑距离是将一个术语转换为另一个术语所需的一个字符更改的次数。这些更改可以包括:</p>
<ul>
<li>更改字符box→ fox</li>
<li>删除字符black→ lack</li>
<li>插入字符sic→ sick</li>
<li>转置两个相邻字符act→ cat</li>
</ul>
<pre><code class="language-bash">GET /test-dsl-term-level/_search
{
&quot;query&quot;: {
&quot;fuzzy&quot;: {
&quot;remarks&quot;: {
&quot;value&quot;: &quot;hell&quot;
}
}
}
}
</code></pre>
<p><img src="assets/es-dsl-term-11.png" alt="img" /></p>
<h2>参考文章</h2>
<p>https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996f9edf203d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,838 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>14 原理ES原理知识点补充和整体结构.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>14 原理ES原理知识点补充和整体结构</h1>
<h2>ElasticSearch整体结构</h2>
<blockquote>
<p>通过上文在通过图解了解了ES整体的原理后我们梳理下ES的整体结构</p>
</blockquote>
<p><img src="assets/es-th-2-3.png" alt="img" /></p>
<ul>
<li>一个 ES Index 在集群模式下,有多个 Node (节点)组成。每个节点就是 ES 的Instance (实例)。</li>
<li>每个节点上会有多个 shard (分片), P1 P2 是主分片, R1 R2 是副本分片</li>
<li>每个分片上对应着就是一个 Lucene Index底层索引文件</li>
<li>Lucene Index 是一个统称
<ul>
<li>由多个 Segment (段文件,就是倒排索引)组成。每个段文件存储着就是 Doc 文档。</li>
<li>commit point记录了所有 segments 的信息</li>
</ul>
</li>
</ul>
<h2>补充:Lucene索引结构</h2>
<blockquote>
<p>上图中Lucene的索引结构中有哪些文件呢</p>
</blockquote>
<p><img src="assets/es-th-2-2.png" alt="img" /></p>
<p>(更多文件类型可参考<a href="https://lucene.apache.org/core/7_2_1/core/org/apache/lucene/codecs/lucene70/package-summary.html#package.description">这里 </a></p>
<p><img src="assets/es-th-3-1.png" alt="img" /></p>
<p>文件的关系如下:</p>
<p><img src="assets/es-th-3-2.jpeg" alt="img" /></p>
<h2>补充:Lucene处理流程</h2>
<blockquote>
<p>上文图解过程还需要理解Lucene处理流程, 这将帮助你更好的索引文档和搜索文档。</p>
</blockquote>
<p><img src="assets/es-th-3-21.jpeg" alt="img" /></p>
<p>创建索引的过程:</p>
<ul>
<li>准备待索引的原文档,数据来源可能是文件、数据库或网络</li>
<li>对文档的内容进行分词组件处理形成一系列的Term</li>
<li>索引组件对文档和Term处理形成字典和倒排表</li>
</ul>
<p>搜索索引的过程:</p>
<ul>
<li>对查询语句进行分词处理形成一系列Term</li>
<li>根据倒排索引表查找出包含Term的文档并进行合并形成符合结果的文档集</li>
<li>比对查询语句与各个文档相关性得分,并按照得分高低返回</li>
</ul>
<h2>补充:ElasticSearch分析器</h2>
<blockquote>
<p>上图中很重要的一项是<strong>语法分析/语言处理</strong>, 所以我们还需要补充ElasticSearch分析器知识点。</p>
</blockquote>
<p>分析 包含下面的过程:</p>
<ul>
<li>首先,将一块文本分成适合于倒排索引的独立的 词条 </li>
<li>之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall</li>
</ul>
<p>分析器执行上面的工作。 分析器 实际上是将三个功能封装到了一个包里:</p>
<ul>
<li><strong>字符过滤器</strong> 首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML或者将 &amp; 转化成 and。</li>
<li><strong>分词器</strong> 其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。</li>
<li><strong>Token 过滤器</strong> 最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 a and the 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。</li>
</ul>
<p>Elasticsearch提供了开箱即用的字符过滤器、分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的。</p>
<h3>内置分析器</h3>
<p>Elasticsearch还附带了可以直接使用的预包装的分析器。接下来我们会列出最重要的分析器。为了证明它们的差异我们看看每个分析器会从下面的字符串得到哪些词条</p>
<pre><code class="language-bash">&quot;Set the shape to semi-transparent by calling set_trans(5)&quot;
</code></pre>
<ul>
<li><strong>标准分析器</strong></li>
</ul>
<p>标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 Unicode 联盟 定义的 <strong>单词边界</strong> 划分文本。删除绝大部分标点。最后,将词条小写。它会产生</p>
<pre><code class="language-bash">set, the, shape, to, semi, transparent, by, calling, set_trans, 5
</code></pre>
<ul>
<li><strong>简单分析器</strong></li>
</ul>
<p>简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生</p>
<pre><code class="language-bash">set, the, shape, to, semi, transparent, by, calling, set, trans
</code></pre>
<ul>
<li><strong>空格分析器</strong></li>
</ul>
<p>空格分析器在空格的地方划分文本。它会产生</p>
<pre><code class="language-bash">Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
</code></pre>
<ul>
<li><strong>语言分析器</strong></li>
</ul>
<p>特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语 分析器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。</p>
<p>英语 分词器会产生下面的词条:</p>
<pre><code class="language-bash">set, shape, semi, transpar, call, set_tran, 5
</code></pre>
<p>注意看 transparent、 calling 和 set_trans 已经变为词根格式。</p>
<h3>什么时候使用分析器</h3>
<p>当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析过程 ,以保证我们搜索的词条格式与索引中的词条格式一致。</p>
<p>全文查询,理解每个域是如何定义的,因此它们可以做正确的事:</p>
<ul>
<li>当你查询一个 全文 域时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表。</li>
<li>当你查询一个 精确值 域时,不会分析查询字符串,而是搜索你指定的精确值。</li>
</ul>
<blockquote>
<p>举个例子</p>
</blockquote>
<p>ES中每天一条数据 按照如下方式查询:</p>
<pre><code class="language-bash">GET /_search?q=2014 # 12 results
GET /_search?q=2014-09-15 # 12 results !
GET /_search?q=date:2014-09-15 # 1 result
GET /_search?q=date:2014 # 0 results !
</code></pre>
<p>为什么返回那样的结果?</p>
<ul>
<li>date 域包含一个精确值:单独的词条 2014-09-15。</li>
<li>_all 域是一个全文域,所以分词进程将日期转化为三个词条: 2014 09 和 15。</li>
</ul>
<p>当我们在 _all 域查询 2014它匹配所有的12条推文因为它们都含有 2014 </p>
<pre><code class="language-bash">GET /_search?q=2014 # 12 results
</code></pre>
<p>当我们在 _all 域查询 2014-09-15它首先分析查询字符串产生匹配 2014 09 或 15 中 任意 词条的查询。这也会匹配所有12条推文因为它们都含有 2014 </p>
<pre><code class="language-bash">GET /_search?q=2014-09-15 # 12 results !
</code></pre>
<p>当我们在 date 域查询 2014-09-15它寻找 精确 日期,只找到一个推文:</p>
<pre><code class="language-bash">GET /_search?q=date:2014-09-15 # 1 result
</code></pre>
<p>当我们在 date 域查询 2014它找不到任何文档因为没有文档含有这个精确日志</p>
<pre><code class="language-bash">GET /_search?q=date:2014 # 0 results !
</code></pre>
<h2>参考文章</h2>
<p>https://new.qq.com/omn/20210320/20210320A01XHF00.html</p>
<p>https://juejin.cn/post/6844903473666867208</p>
<p>http://lucene.apache.org/core/7_2_1/core/org/apache/lucene/codecs/lucene70/package-summary.html#package.description</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996faa39713d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,948 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>16 原理ES原理之读取文档流程详解.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>16 原理ES原理之读取文档流程详解</h1>
<h2>文档查询步骤顺序</h2>
<blockquote>
<p>先看下整体的查询流程</p>
</blockquote>
<h3>单个文档</h3>
<p>以下是从主分片或者副本分片检索文档的步骤顺序:</p>
<p><img src="assets/es-th-2-21.png" alt="img" /></p>
<ol>
<li>客户端向 Node 1 发送获取请求。</li>
<li>节点使用文档的 _id 来确定文档属于分片 0 。分片 0 的副本分片存在于所有的三个节点上。 在这种情况下,它将请求转发到 Node 2 。</li>
<li>Node 2 将文档返回给 Node 1 ,然后将文档返回给客户端。</li>
</ol>
<p>在处理读取请求时,协调结点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。</p>
<p>在文档被检索时,已经被索引的文档可能已经存在于主分片上但是还没有复制到副本分片。 在这种情况下,副本分片可能会报告文档不存在,但是主分片可能成功返回文档。 一旦索引请求成功返回给用户,文档在主分片和副本分片都是可用的。</p>
<h3>多个文档</h3>
<p>使用 mget 取回多个文档的步骤顺序:</p>
<p><img src="assets/es-th-2-22.png" alt="img" /></p>
<p>以下是使用单个 mget 请求取回多个文档所需的步骤顺序:</p>
<ol>
<li>客户端向 Node 1 发送 mget 请求。</li>
<li>Node 1 为每个分片构建多文档获取请求,然后并行转发这些请求到托管在每个所需的主分片或者副本分片的节点上。一旦收到所有答复, Node 1 构建响应并将其返回给客户端。</li>
</ol>
<h2>文档读取过程详解</h2>
<blockquote>
<p>所有的搜索系统一般都是两阶段查询第一阶段查询到匹配的DocID第二阶段再查询DocID对应的完整文档这种在Elasticsearch中称为query_then_fetch。这里主要介绍最常用的2阶段查询其它方式可以参考<a href="https://zhuanlan.zhihu.com/p/34674517">这里 </a>)。</p>
</blockquote>
<p><img src="assets/es-th-2-32.jpeg" alt="img" /></p>
<ol>
<li>在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。PS在2. 搜索的时候是会查询Filesystem Cache的但是有部分数据还在Memory Buffer所以搜索是近实时的。</li>
<li>每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。</li>
<li>接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并丰富文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。</li>
</ol>
<h2>深入ElasticSearch读取文档的实现机制</h2>
<p>TIP</p>
<p>作为选读内容。</p>
<h3>读操作</h3>
<p>一致性指的是写入成功后下次读操作一定要能读取到最新的数据。对于搜索这个要求会低一些可以有一些延迟。但是对于NoSQL数据库则一般要求最好是强一致性的。</p>
<p>结果匹配上NoSQL作为数据库查询过程中只有符合不符合两种情况而搜索里面还有是否相关类似于NoSQL的结果只能是0或1而搜索里面可能会有0.10.50.9等部分匹配或者更相关的情况。</p>
<p>结果召回上搜索一般只需要召回最满足条件的Top N结果即可而NoSQL一般都需要返回满足条件的所有结果。</p>
<p>搜索系统一般都是两阶段查询第一个阶段查询到对应的Doc ID也就是PK第二阶段再通过Doc ID去查询完整文档而NoSQL数据库一般是一阶段就返回结果。在Elasticsearch中两种都支持。</p>
<p>目前NoSQL的查询聚合、分析和统计等功能上都是要比搜索弱的。</p>
<h3>Lucene的读</h3>
<p>Elasticsearch使用了Lucene作为搜索引擎库通过Lucene完成特定字段的搜索等功能在Lucene中这个功能是通过IndexSearcher的下列接口实现的</p>
<pre><code class="language-java">public TopDocs search(Query query, int n);
public Document doc(int docID);
public int count(Query query);
......(其他)
</code></pre>
<p>第一个search接口实现搜索功能返回最满足Query的N个结果第二个doc接口通过doc id查询Doc内容第三个count接口通过Query获取到命中数。</p>
<p>这三个功能是搜索中的最基本的三个功能点对于大部分Elasticsearch中的查询都是比较复杂的直接用这个接口是无法满足需求的比如分布式问题。这些问题都留给了Elasticsearch解决我们接下来看Elasticsearch中相关读功能的剖析。</p>
<h3>Elasticsearch的读</h3>
<p>Elasticsearch中每个Shard都会有多个Replica主要是为了保证数据可靠性除此之外还可以增加读能力因为写的时候虽然要写大部分Replica Shard但是查询的时候只需要查询Primary和Replica中的任何一个就可以了。</p>
<p><img src="assets/es-th-3-7.jpeg" alt="img" /></p>
<p>在上图中该Shard有1个Primary和2个Replica Node当查询的时候从三个节点中根据Request中的preference参数选择一个节点查询。preference可以设置_local_primary_replica以及其他选项。如果选择了primary则每次查询都是直接查询Primary可以保证每次查询都是最新的。如果设置了其他参数那么可能会查询到R1或者R2这时候就有可能查询不到最新的数据。</p>
<p>PS: 上述代码逻辑在OperationRouting.Java的searchShards方法中。</p>
<p>接下来看一下Elasticsearch中的查询是如何支持分布式的。</p>
<p><img src="assets/es-th-3-8.jpeg" alt="img" /></p>
<p>Elasticsearch中通过分区实现分布式数据写入的时候根据_routing规则将数据写入某一个Shard中这样就能将海量数据分布在多个Shard以及多台机器上已达到分布式的目标。这样就导致了查询的时候潜在数据会在当前index的所有的Shard中所以Elasticsearch查询的时候需要查询所有Shard同一个Shard的Primary和Replica选择一个即可查询请求会分发给所有Shard每个Shard中都是一个独立的查询引擎比如需要返回Top 10的结果那么每个Shard都会查询并且返回Top 10的结果然后在Client Node里面会接收所有Shard的结果然后通过优先级队列二次排序选择出Top 10的结果返回给用户。</p>
<p>这里有一个问题就是请求膨胀用户的一个搜索请求在Elasticsearch内部会变成Shard个请求这里有个优化点虽然是Shard个请求但是这个Shard个数不一定要是当前Index中的Shard个数只要是当前查询相关的Shard即可这个需要基于业务和请求内容优化通过这种方式可以优化请求膨胀数。</p>
<p>Elasticsearch中的查询主要分为两类<strong>Get请求</strong>通过ID查询特定Doc<strong>Search请求</strong>通过Query查询匹配Doc。</p>
<p><img src="assets/es-th-3-9.jpeg" alt="img" /></p>
<p>PS:上图中内存中的Segment是指刚Refresh Segment但是还没持久化到磁盘的新Segment而非从磁盘加载到内存中的Segment。</p>
<p>对于Search类请求查询的时候是一起查询内存和磁盘上的Segment最后将结果合并后返回。这种查询是近实时Near Real Time主要是由于内存中的Index数据需要一段时间后才会刷新为Segment。</p>
<p>对于Get类请求查询的时候是先查询内存中的TransLog如果找到就立即返回如果没找到再查询磁盘上的TransLog如果还没有则再去查询磁盘上的Segment。这种查询是实时Real Time的。这种查询顺序可以保证查询到的Doc是最新版本的Doc这个功能也是为了保证NoSQL场景下的实时性要求。</p>
<p><img src="assets/es-th-3-10.jpeg" alt="img" /></p>
<p>所有的搜索系统一般都是两阶段查询第一阶段查询到匹配的DocID第二阶段再查询DocID对应的完整文档这种在Elasticsearch中称为query_then_fetch还有一种是一阶段查询的时候就返回完整Doc在Elasticsearch中称作query_and_fetch一般第二种适用于只需要查询一个Shard的请求。</p>
<p>除了一阶段两阶段外还有一种三阶段查询的情况。搜索里面有一种算分逻辑是根据TFTerm Frequency和DFDocument Frequency计算基础分但是Elasticsearch中查询的时候是在每个Shard中独立查询的每个Shard中的TF和DF也是独立的虽然在写入的时候通过_routing保证Doc分布均匀但是没法保证TF和DF均匀那么就有会导致局部的TF和DF不准的情况出现这个时候基于TF、DF的算分就不准。为了解决这个问题Elasticsearch中引入了DFS查询比如DFS_query_then_fetch会先收集所有Shard中的TF和DF值然后将这些值带入请求中再次执行query_then_fetch这样算分的时候TF和DF就是准确的类似的有DFS_query_and_fetch。这种查询的优势是算分更加精准但是效率会变差。另一种选择是用BM25代替TF/DF模型。</p>
<p>在新版本Elasticsearch中用户没法指定DFS_query_and_fetch和query_and_fetch这两种只能被Elasticsearch系统改写。</p>
<h3>Elasticsearch查询流程</h3>
<p>Elasticsearch中的大部分查询以及核心功能都是Search类型查询上面我们了解到查询分为一阶段二阶段和三阶段这里我们就以最常见的的二阶段查询为例来介绍查询流程。</p>
<p><img src="assets/es-th-2-31.jpeg" alt="img" /></p>
<h4>Client Node</h4>
<blockquote>
<p>Client Node 也包括了前面说过的Parse Request这里就不再赘述了接下来看一下其他的部分。</p>
</blockquote>
<ol>
<li><strong>Get Remove Cluster Shard</strong></li>
</ol>
<p>判断是否需要跨集群访问如果需要则获取到要访问的Shard列表。</p>
<ol>
<li><strong>Get Search Shard Iterator</strong></li>
</ol>
<p>获取当前Cluster中要访问的Shard和上一步中的Remove Cluster Shard合并构建出最终要访问的完整Shard列表。</p>
<p>这一步中会根据Request请求中的参数从Primary Node和多个Replica Node中选择出一个要访问的Shard。</p>
<ol>
<li><strong>For Every Shard:Perform</strong></li>
</ol>
<p>遍历每个Shard对每个Shard执行后面逻辑。</p>
<ol>
<li><strong>Send Request To Query Shard</strong></li>
</ol>
<p>将查询阶段请求发送给相应的Shard。</p>
<ol>
<li><strong>Merge Docs</strong></li>
</ol>
<p>上一步将请求发送给多个Shard后这一步就是异步等待返回结果然后对结果合并。这里的合并策略是维护一个Top N大小的优先级队列每当收到一个shard的返回就把结果放入优先级队列做一次排序直到所有的Shard都返回。</p>
<p>翻页逻辑也是在这里如果需要取Top 30~ Top 40的结果这个的意思是所有Shard查询结果中的第30到40的结果那么在每个Shard中无法确定最终的结果每个Shard需要返回Top 40的结果给Client Node然后Client Node中在merge docs的时候计算出Top 40的结果最后再去除掉Top 30剩余的10个结果就是需要的Top 30~ Top 40的结果。</p>
<p>上述翻页逻辑有一个明显的缺点就是每次Shard返回的数据中包括了已经翻过的历史结果如果翻页很深则在这里需要排序的Docs会很多比如Shard有1000取第9990到10000的结果那么这次查询Shard总共需要返回1000 * 10000也就是一千万Doc这种情况很容易导致OOM。</p>
<p>另一种翻页方式是使用search_after这种方式会更轻量级如果每次只需要返回10条结构则每个Shard只需要返回search_after之后的10个结果即可返回的总数据量只是和Shard个数以及本次需要的个数有关和历史已读取的个数无关。这种方式更安全一些推荐使用这种。</p>
<p>如果有aggregate也会在这里做聚合但是不同的aggregate类型的merge策略不一样具体的可以在后面的aggregate文章中再介绍。</p>
<ol>
<li><strong>Send Request To Fetch Shard</strong></li>
</ol>
<p>选出Top N个Doc ID后发送给这些Doc ID所在的Shard执行Fetch Phase最后会返回Top N的Doc的内容。</p>
<h4>Query Phase</h4>
<blockquote>
<p>接下来我们看第一阶段查询的步骤:</p>
</blockquote>
<ol>
<li><strong>Create Search Context</strong></li>
</ol>
<p>创建Search Context之后Search过程中的所有中间状态都会存在Context中这些状态总共有50多个具体可以查看DefaultSearchContext或者其他SearchContext的子类。</p>
<ol>
<li><strong>Parse Query</strong></li>
</ol>
<p>解析Query的Source将结果存入Search Context。这里会根据请求中Query类型的不同创建不同的Query对象比如TermQuery、FuzzyQuery等最终真正执行TermQuery、FuzzyQuery等语义的地方是在Lucene中。</p>
<p>这里包括了dfsPhase、queryPhase和fetchPhase三个阶段的preProcess部分只有queryPhase的preProcess中有执行逻辑其他两个都是空逻辑执行完preProcess后所有需要的参数都会设置完成。</p>
<p>由于Elasticsearch中有些请求之间是相互关联的并非独立的比如scroll请求所以这里同时会设置Context的生命周期。</p>
<p>同时会设置lowLevelCancellation是否打开这个参数是集群级别配置同时也能动态开关打开后会在后面执行时做更多的检测检测是否需要停止后续逻辑直接返回。</p>
<ol>
<li><strong>Get From Cache</strong></li>
</ol>
<p>判断请求是否允许被Cache如果允许则检查Cache中是否已经有结果如果有则直接读取Cache如果没有则继续执行后续步骤执行完后再将结果加入Cache。</p>
<ol>
<li><strong>Add Collectors</strong></li>
</ol>
<p>Collector主要目标是收集查询结果实现排序对自定义结果集过滤和收集等。这一步会增加多个Collectors多个Collector组成一个List。</p>
<ul>
<li>FilteredCollector先判断请求中是否有Post FilterPost Filter用于SearchAgg等结束后再次对结果做Filter希望Filter不影响Agg结果。如果有Post Filter则创建一个FilteredCollector加入Collector List中。</li>
<li>PluginInMultiCollector判断请求中是否制定了自定义的一些Collector如果有则创建后加入Collector List。</li>
<li>MinimumScoreCollector判断请求中是否制定了最小分数阈值如果指定了则创建MinimumScoreCollector加入Collector List中在后续收集结果时会过滤掉得分小于最小分数的Doc。</li>
<li>EarlyTerminatingCollector判断请求中是否提前结束Doc的Seek如果是则创建EarlyTerminatingCollector加入Collector List中。在后续Seek和收集Doc的过程中当Seek的Doc数达到Early Terminating后会停止Seek后续倒排链。</li>
<li>CancellableCollector判断当前操作是否可以被中断结束比如是否已经超时等如果是会抛出一个TaskCancelledException异常。该功能一般用来提前结束较长的查询请求可以用来保护系统。</li>
<li>EarlyTerminatingSortingCollector如果Index是排序的那么可以提前结束对倒排链的Seek相当于在一个排序递减链表上返回最大的N个值只需要直接返回前N个值就可以了。这个Collector会加到Collector List的头部。EarlyTerminatingSorting和EarlyTerminating的区别是EarlyTerminatingSorting是一种对结果无损伤的优化而EarlyTerminating是有损的人为掐断执行的优化。</li>
<li>TopDocsCollector这个是最核心的Top N结果选择器会加入到Collector List的头部。TopScoreDocCollector和TopFieldCollector都是TopDocsCollector的子类TopScoreDocCollector会按照固定的方式算分排序会按照分数+doc id的方式排列如果多个doc的分数一样先选择doc id小的文档。而TopFieldCollector则是根据用户指定的Field的值排序。</li>
</ul>
<ol>
<li><strong>lucene::search</strong></li>
</ol>
<p>这一步会调用Lucene中IndexSearch的search接口执行真正的搜索逻辑。每个Shard中会有多个Segment每个Segment对应一个LeafReaderContext这里会遍历每个Segment到每个Segment中去Search结果然后计算分数。</p>
<p>搜索里面一般有两阶段算分第一阶段是在这里算的会对每个Seek到的Doc都计算分数为了减少CPU消耗一般是算一个基本分数。这一阶段完成后会有个排序。然后在第二阶段再对Top 的结果做一次二阶段算分,在二阶段算分的时候会考虑更多的因子。二阶段算分在后续操作中。</p>
<p>具体请求比如TermQuery、WildcardQuery的查询逻辑都在Lucene中后面会有专门文章介绍。</p>
<ol>
<li><strong>rescore</strong></li>
</ol>
<p>根据Request中是否包含rescore配置决定是否进行二阶段排序如果有则执行二阶段算分逻辑会考虑更多的算分因子。二阶段算分也是一种计算机中常见的多层设计是一种资源消耗和效率的折中。</p>
<p>Elasticsearch中支持配置多个Rescore这些rescore逻辑会顺序遍历执行。每个rescore内部会先按照请求参数window选择出Top window的doc然后对这些doc排序排完后再合并回原有的Top 结果顺序中。</p>
<ol>
<li><strong>suggest::execute()</strong></li>
</ol>
<p>如果有推荐请求,则在这里执行推荐请求。如果请求中只包含了推荐的部分,则很多地方可以优化。推荐不是今天的重点,这里就不介绍了,后面有机会再介绍。</p>
<ol>
<li>a<strong>ggregation::execute()</strong></li>
</ol>
<p>如果含有聚合统计请求则在这里执行。Elasticsearch中的aggregate的处理逻辑也类似于Search通过多个Collector来实现。在Client Node中也需要对aggregation做合并。aggregate逻辑更复杂一些就不在这里赘述了后面有需要就再单独开文章介绍。</p>
<p>上述逻辑都执行完成后如果当前查询请求只需要查询一个Shard那么会直接在当前Node执行Fetch Phase。</p>
<h4>Fetch Phase</h4>
<p>Elasticsearch作为搜索系统时或者任何搜索系统中除了Query阶段外还会有一个Fetch阶段这个Fetch阶段在数据库类系统中是没有的是搜索系统中额外增加的阶段。搜索系统中额外增加Fetch阶段的原因是搜索系统中数据分布导致的在搜索中数据通过routing分Shard的时候只能根据一个主字段值来决定但是查询的时候可能会根据其他非主字段查询那么这个时候所有Shard中都可能会存在相同非主字段值的Doc所以需要查询所有Shard才能不会出现结果遗漏。同时如果查询主字段那么这个时候就能直接定位到Shard就只需要查询特定Shard即可这个时候就类似于数据库系统了。另外数据库中的二级索引又是另外一种情况但类似于查主字段的情况这里就不多说了。</p>
<p>基于上述原因第一阶段查询的时候并不知道最终结果会在哪个Shard上所以每个Shard中管都需要查询完整结果比如需要Top 10那么每个Shard都需要查询当前Shard的所有数据找出当前Shard的Top 10然后返回给Client Node。如果有100个Shard那么就需要返回100 * 10 = 1000个结果而Fetch Doc内容的操作比较耗费IO和CPU如果在第一阶段就Fetch Doc那么这个资源开销就会非常大。所以一般是当Client Node选择出最终Top N的结果后再对最终的Top N读取Doc内容。通过增加一点网络开销而避免大量IO和CPU操作这个折中是非常划算的。</p>
<p>Fetch阶段的目的是通过DocID获取到用户需要的完整Doc内容。这些内容包括了DocValuesStoreSourceScript和Highlight等具体的功能点是在SearchModule中注册的系统默认注册的有</p>
<ul>
<li>ExplainFetchSubPhase</li>
<li>DocValueFieldsFetchSubPhase</li>
<li>ScriptFieldsFetchSubPhase</li>
<li>FetchSourceSubPhase</li>
<li>VersionFetchSubPhase</li>
<li>MatchedQueriesFetchSubPhase</li>
<li>HighlightPhase</li>
<li>ParentFieldSubFetchPhase</li>
</ul>
<p>除了系统默认的8种外还有通过插件的形式注册自定义的功能这些SubPhase中最重要的是Source和HighlightSource是加载原文Highlight是计算高亮显示的内容片断。</p>
<p>上述多个SubPhase会针对每个Doc顺序执行可能会产生多次的随机IO这里会有一些优化方案但是都是针对特定场景的不具有通用性。</p>
<p>Fetch Phase执行完后整个查询流程就结束了。</p>
<h2>参考文档</h2>
<p>https://www.elastic.co/guide/cn/elasticsearch/guide/current/distrib-read.html</p>
<p>https://www.elastic.co/guide/cn/elasticsearch/guide/current/distrib-multi-doc.html</p>
<p>https://www.elastic.co/guide/cn/elasticsearch/guide/current/inside-a-shard.html</p>
<p>https://zhuanlan.zhihu.com/p/34674517</p>
<p>https://zhuanlan.zhihu.com/p/34669354</p>
<p>https://www.cnblogs.com/yangwenbo214/p/9831479.html</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996faeeccf3d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,884 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>18 大厂实践:腾讯万亿级 Elasticsearch 技术实践</h1>
<h2>一、ES 在腾讯的海量规模背景</h2>
<p><img src="assets/es-tencent-y-2.jpeg" alt="img" /></p>
<p>先来看看 ES 在腾讯的主要应用场景。ES 是一个实时的分布式搜索分析引擎,目前很多用户对 ES 的印象还是准实时,实际上<strong>在 6.8 版本之后官方文档已经将 near real-time 改为了 real-time</strong> &quot;Elasticsearch provides real-time search and analytics for all types of data.&quot; ES 在写入完毕刷新之前,是可以通过 <code>getById</code> 的方式实时获取文档的,只是在刷新之前 FST 还没有构建,还不能提供搜索的能力。 目前 ES 在腾讯主要应用在三个方面:</p>
<ul>
<li><strong>搜索服务</strong> 例如像腾讯文档基于 ES 做全文检索,我们的电商客户拼多多、蘑菇街等大量的商品搜索都是基于 ES。</li>
<li><strong>日志分析</strong> 这个是 ES 应用最广泛的领域支持全栈的日志分析包括各种应用日志、数据库日志、用户行为日志、网络数据、安全数据等等。ES 拥有一套完整的日志解决方案,可以秒级实现从采集到展示。</li>
<li><strong>时序分析</strong> 典型的场景是监控数据分析,比如云监控,整个腾讯云的监控都是基于 ES 的。此外还包括物联网场景也有大量的时序数据。时序数据的特点是写入吞吐量特别高ES 支持的同时也提供了丰富的多维统计分析算子。</li>
</ul>
<p>当然除了上面的场景之外ES 本身在站内搜索、安全、APM 等领域也有广泛的应用。</p>
<p>目前 ES 在腾讯公有云、专有云以及内部云上面均有提供服务,可以广泛的满足公司内外客户的业务需求。公有云上的使用场景非常丰富,专有云主要实现标准化交付和自动化运维,腾讯内部云上的 ES 都是 PB 级的超大规模集群。</p>
<h2>二、痛点与挑战</h2>
<p>在这些丰富的应用场景,以及海量的规模背景下,我们也遇到了很多的痛点与挑战。主要覆盖在可用性、性能、成本以及扩展性方面。</p>
<p><img src="assets/es-tencent-y-3.jpeg" alt="img" /></p>
<ul>
<li><strong>可用性</strong> 最常见的问题是节点因高负载 OOM或者整个集群因高负载而雪崩。这些痛点使我们很难保障 SLA尤其是在搜索场景 可用性要求 4 个 9 以上。</li>
<li><strong>性能</strong> 搜索场景一般要求平响延时低于 20 毫秒,查询毛刺低于 100 毫秒。在分析场景,海量数据下,虽然实时性要求没那么高,但请求响应时间决定了用户体验,资源消耗决定了性能边界。</li>
<li><strong>成本</strong> 很多用户都比较关注 ES 的存储成本,因为 ES 确实数据类型较多压缩比比较低存储成本比较高但是优化的空间还是很大的。另外还包括内存成本ES 有大量的索引数据需要加载到内存提供高性能的搜索能力。那么对于日志、监控等海量场景,成本的挑战就更大。</li>
<li><strong>扩展性</strong> 日志、时序等场景,往往索引会按周期滚动,长周期会产生大量的索引和分片,超大规模集群甚至有几十上百万的分片、千级节点的需求。而目前原生版本 ES 只能支持到万级分片、百级节点。随着大数据领域的飞速发展ES 最终是要突破 TB 的量级,跨越到 PB 的量级,扩展性就成为了主要的瓶颈与挑战。</li>
</ul>
<h2>三、腾讯 ES 内核优化剖析</h2>
<blockquote>
<p>ES 使用姿势、参数调优等在社区有很多的案例和经验可以借鉴,但很多的痛点和挑战是无法通过简单的调优来解决的,这个时候就需要从内核层面做深度的优化,来不断完善这个优秀的开源产品。接下来就是本次分享的核心部分,我们来看看腾讯是如何在内核层面对 ES 做优化的。</p>
</blockquote>
<p><img src="assets/es-tencent-y-4.jpeg" alt="img" /></p>
<h3>可用性优化</h3>
<p>首先介绍可用性优化部分。总体来说,原生版本在可用性层面有三个层面的问题:</p>
<ul>
<li><strong>系统健壮性不足</strong> 高压力下集群雪崩,主要原因是内存资源不足。负载不均会导致部分节点压力过载,节点 OOM。我们在这个层面的方案主要是优化服务限流和节点均衡策略。</li>
<li><strong>容灾方案欠缺</strong> ES 本身提供副本机制提升数据安全性对于多可用区容灾还是需要云平台额外实现。即使有副本机制甚至有跨集群复制CCR但还是不能阻挡用户误操作导致的数据删除所以还需要额外提供低成本的备份回挡能力。</li>
<li><strong>内核 Bug</strong> 我们修复了 Master 任务堵塞、分布式死锁、滚动重启速度慢等一系列内核可用性相关的问题,并及时提供新版本给用户升级。</li>
</ul>
<p>接下来针对用户在可用性层面常遇到的两类问题展开分析。一类是高并发请求压垮集群,另一类是单个大查询打挂节点。</p>
<h4>高并发请求压垮集群</h4>
<p><img src="assets/es-tencent-y-5.jpeg" alt="img" /></p>
<p>先来看第一类场景,高并发请求压垮集群。例如早期我们内部一个日志集群,写入量一天突增 5 倍,集群多个节点 Old GC 卡住脱离集群,集群 RED写入停止这个痛点确实有点痛。我们对挂掉的节点做了内存分析发现大部分内存是被反序列化前后的写入请求占用。我们来看看这些写入请求是堆积在什么位置。</p>
<p><img src="assets/es-tencent-y-6.jpeg" alt="img" /></p>
<p>ES high level 的写入流程,用户的写入请求先到达其中一个数据节点,我们称之为数据节点。然后由该协调节点将请求转发给主分片所在节点进行写入,主分片写入完毕再由主分片转发给从分片写入,最后返回给客户端写入结果。右边是更细节的写入流程,而我们从堆栈中看到的写入请求堆积的位置就是在红色框中的接入层,节点挂掉的根因是协调节点的接入层内存被打爆。</p>
<p>找到了问题的原因,接下来介绍我们的<strong>优化方案</strong></p>
<p><img src="assets/es-tencent-y-7.jpeg" alt="img" /></p>
<p>针对这种高并发场景,我们的优化方案是服务限流。除了要能控制并发请求数量,还要能精准的控制内存资源,因为内存资源不足是主要的矛盾。另外通用性要强,能作用于各个层级实现全链限流。</p>
<p>限流方案,很多数据库使用场景会采用从业务端或者独立的 proxy 层配置相关的业务规则,做资源预估等方式进行限流。这种方式适应能力弱,运维成本高,而且业务端很难准确的预估资源消耗。</p>
<p>原生版本本身有限流策略,是基于请求数的漏桶策略,通过队列加线程池的方式实现。线程池大小决定的了处理并发度,处理不完放到队列,队列放不下则拒绝请求。但是单纯的基于请求数的限流不能控制资源使用量,而且只作用于分片级子请求的传输层,对于我们前面分析的接入层无法起到有效的保护作用。原生版本也有内存熔断策略,但是在协调节点接入层并没有做限制。</p>
<p>我们的优化方案是基于内存资源的漏桶策略。我们将节点 JVM 内存作为漏桶的资源,当内存资源足够的时候,请求可以正常处理,当内存使用量到达一定阈值的时候分区间阶梯式平滑限流。例如图中浅黄色的区间限制写入,深黄色的区间限制查询,底部红色部分作为预留 buffer预留给处理中的请求、merge 等操作,以保证节点内存的安全性。</p>
<p><img src="assets/es-tencent-y-8.jpeg" alt="img" /></p>
<p>限流方案里面有一个挑战是,我们如何才能实现平滑限流?因为采用单一的阈值限流很容易出现请求抖动,例如请求一上来把内存打上去马上触发限流,而放开一点点请求又会涌进来把内存打上去。我们的方案是设置了高低限流阈值区间,在这个区间中,基于余弦变换实现请求数和内存资源之间的平滑限流。当内存资源足够的时候,请求通过率 100%,当内存到达限流区间逐步上升的时候,请求通过率随之逐步下降。而当内存使用量下降的时候,请求通过率也会逐步上升,不会一把放开。通过实际测试,平滑的区间限流能在高压力下保持稳定的写入性能。</p>
<p>我们基于内存资源的区间平滑限流策略是对原生版本基于请求数漏桶策略的有效补充,并且作用范围更广,覆盖协调节点、数据节点的接入层和传输层,并不会替代原生的限流方案。</p>
<p><img src="assets/es-tencent-y-9.jpeg" alt="img" /></p>
<h4>单个大查询打挂节点</h4>
<p>接下来介绍单个大查询打挂节点的场景。例如我们在分析场景,做多层嵌套聚合,有时候请求返回的结果集比较大,那么这个时候极有可能这一个请求就会将节点打挂。我们对聚合查询流程进行分析,请求到达协调节点之后,会拆分为分片级子查询请求给目标分片所在数据节点进行子聚合,最后协调节点收集到完整的分片结果后进行归并、聚合、排序等操作。这里的主要问题点是,协调节点大量汇聚结果反序列化后内存膨胀,以及二次聚合产生新的结果集打爆内存。</p>
<p><img src="assets/es-tencent-y-10.jpeg" alt="img" /></p>
<p>针对上面单个大查询的问题,下面介绍我们的优化方案。优化方案的要点是内存膨胀预估加流式检查。 我们先来看下原生方案,原生版本是直接限制最大返回结果桶数,默认一万,超过则请求返回异常。这种方式面临的挑战是,在分析场景结果数十万、百万是常态,默认一万往往不够,调整不灵活,调大了内存可能还是会崩掉,小了又不能满足业务需求。</p>
<p>我们的优化方案主要分为两个阶段:</p>
<ul>
<li>第一阶段:在协调节点接收数据节点返回的响应结果反序列化之前做内存膨胀预估,基于接收到的网络 byte 流大小做膨胀预估,如果当前 JVM 内存使用量加上响应结果预估的使用量超过阈值则直接熔断请求。</li>
<li>第二阶段:在协调节点 reduce 过程中,流式检查桶数,每增加固定数量的桶(默认 1024 个)检查一次内存,如果超限则直接熔断。流式检查的逻辑在数据节点子聚合的过程同样生效。</li>
</ul>
<p>这样用户不再需要关心最大桶数,只要内存足够就能最大化地满足业务需求。不足之处是大请求还是被拒掉了,牺牲了用户的查询体验,但是我们可以通过官方已有的 batch reduce 的方式缓解,就是当有 100 个分片子结果的时候,每收到部分就先做一次聚合,这样能降低单次聚合的内存开销。上面流式聚合的整体方案已经提交给官方并合并了,将在最近的 7.7.0 版本中发布。</p>
<p>前面介绍了两种比较典型的用户常遇到的可用性问题。接下来对整个可用性优化做一个总结。</p>
<p><img src="assets/es-tencent-y-11.jpeg" alt="img" /></p>
<p>首先我们结合自研的优化方案和原生的方案实现了系统性的全链路限流。左图中黄色部分为自研优化,其它为原生方案。覆盖执行引擎层、传输层和接入层。另外我们对内存也做了相关的优化,内存利用率优化主要是针对写入场景,例如单条文档字段数过多上千个,每个字段值在写入过程中都会申请固定大小的 buffer字段数过多的时候内存浪费严重优化方案主要是实现弹性的内存 buffer。内存回收策略这里不是指 GC 策略主要是对于有些例如读写异常的请求及时进行内存回收。JVM GC 债务管理主要是评估 JVM Old GC 时长和正常工作时长的比例来衡量 JVM 的健康情况,特殊情况会重启 JVM 以防止长时间 hang死。</p>
<p>可用性优化效果,我们将公有云的 ES 集群整体可用性提升至 4 个 9内存利用率提升 30%,高压力场景稳定性有大幅提升,基本能保证节点不会 OOM集群不会雪崩。</p>
<p>下面部分是我们可用性优化相关的 PR。除了前面介绍的协调节点流式检查和内存膨胀预估以外还包括单个查询内存限制这个也很有用因为有些场景如果单个查询太大会影响其它所有的请求。以及滚动重启速度优化大集群单个节点的重启时间从 10 分钟降至 1 分钟以内,这个优化在 7.5 版本已经被合并了。如果大家遇到大集群滚动重启效率问题可以关注。</p>
<h3>性能优化</h3>
<p>接下来介绍性能优化。</p>
<p><img src="assets/es-tencent-y-12.jpeg" alt="img" /></p>
<p>性能优化的场景主要分为写入和查询。写入的代表场景包括日志、监控等海量时序数据场景,一般能达到千万级吞吐。带 id 的写入性能衰减一倍因为先要查询记录是否存在。查询包含搜索场景和分析场景搜索服务主要是高并发低延时。聚合分析主要以大查询为主内存、CPU 开销高。</p>
<p>我们看下性能的影响面,左半部分硬件资源和系统调优一般是用户可以直接掌控的,比如资源不够扩容,参数深度调优等。右半部分存储模型和执行计划涉及到内核优化,用户一般不容易直接调整。接下来我们重点介绍一下这两部分的优化。</p>
<p><img src="assets/es-tencent-y-13.jpeg" alt="img" /></p>
<h4>存储模型优化</h4>
<p><img src="assets/es-tencent-y-14.jpeg" alt="img" /></p>
<p>首先是存储模型优化。我们知道 ES 底层 Lucene 是基于 LSM Tree 的数据文件。原生默认的合并策略是按文件大小相似性合并,默认一次固定合并 10 个文件,近似分层合并。这种合并方式的最大优点是合并高效,可以快速降低文件数;主要问题是数据不连续,这样会导致我们在查询的时候文件裁剪的能力很弱,比如查询最近一小时的数据,很有可能一小时的文件被分别合并到了几天前的文件中去了,导致需要遍历的文件增加了。</p>
<p>业内典型的解决数据连续性的合并策略,比如以 Cassandra、HBase 为代表的基于时间窗口的合并策略,优点是数据按时间序合并,查询高效,且可以支持表内 TTL不足是限制只能是时序场景而且文件大小可能不一致从而影响合并效率。还有一类是以 LevelDB、RocksDB 为代表的分层合并,一层一组有序,每次抽取部分数据向下层合并,优点是查询高效,但是写放大比较严重,相同的数据可能会被多次合并,影响写入吞吐。</p>
<p>最后是我们的优化合并策略。我们的目标是为了提升数据连续性、收敛文件数量,提升文件的裁剪能力来提高查询性能。我们实现的策略主要是按时间序分层合并,每层文件之间按创建时间排序,除了第一层外,都按照时间序和目标大小进行合并,不固定每次合并文件数量,这样保证了合并的高效性。对于少量的未合并的文件以及冷分片文件,我们采用持续合并的策略,将超过默认五分钟不再写入的分片进行持续合并,并控制合并并发和范围,以降低合并开销。</p>
<p>通过对合并策略的优化,我们将搜索场景的查询性能提升了 40%。</p>
<h4>执行引擎的优化</h4>
<p>前面介绍了底层文件的存储模型优化,我们再来向上层看看执行引擎的优化。</p>
<p><img src="assets/es-tencent-y-15.jpeg" alt="img" /></p>
<p>我们拿一个典型的场景来进行分析。ES 里面有一种聚合叫 Composite 聚合大家可能都比较了解,这个功能是在 6.5 版本正式 GA 发布的。它的目的是为了支持多字段的嵌套聚合,类似 MySQL 的 group by 多个字段;另外可以支持流式聚合,即以翻页的形式分批聚合结果。用法就像左边贴的查询时聚合操作下面指定 composite 关键字,并指定一次翻页的长度,和 group by 的字段列表。那么每次拿到的聚合结果会伴随着一个 after key 返回,下一次查询拿着这个 after key 就可以查询下一页的结果。</p>
<p>那么它的实现原理是怎样的呢我们先来看看原生的方案。比如这里有两个字段的文档field1 和 field2第一列是文档 id 。我们按照这两个字段进行 composite 聚合,并设定一次翻页的 size 是 3。具体实现是利用一个固定 size 的大顶堆size 就是翻页的长度,全量遍历一把所有文档迭代构建这个基于大顶堆的聚合结果,如右图中的 1 号序列所示,最后返回这个大顶堆并将堆顶作为 after key。第二次聚合的时候同样的全量遍历一把文档但会加上过滤条件排除不符合 after key 的文档,如右图中 2 号序列所示。</p>
<p>很显然这里面存在性能问题,因为每次拉取结果都需要全量遍历一遍所有文档,并未实现真正的翻页。接下来我们提出优化方案。</p>
<p><img src="assets/es-tencent-y-16.jpeg" alt="img" /></p>
<p>我们的优化方案主要是利用 index sorting 实现 after key 跳转以及提前结束early termination。 数据有序才能实现真正的流式聚合index sorting 也是在 6.5 版本里面引入的,可以支持文档按指定字段排序。但遗憾的是聚合查询并没有利用数据有序性。我们可以进行优化,此时大顶堆我们仍然保留,我们只需要按照文档的顺序提取指定 size 的文档数即可马上返回,因为数据有序。下一次聚合的时候,我们可以直接根据请求携带的 after key 做跳转,直接跳转到指定位置继续向后遍历指定 size 的文档数即可返回。这样避免了每次翻页全量遍历,大幅提升查询性能。这里有一个挑战点,假设数据的顺序和用户查询的顺序不一致优化还能生效吗?实际可以的,逆序场景不能实现 after key 跳转因为 lucene 底层不能支持文档反向遍历,但提前结束的优化仍然生效,仍然可以大幅提升效率。这个优化方案我们是和官方研发协作开发的,因为我们在优化的同时,官方也在优化,但我们考虑的更全面覆盖了数据顺序和请求顺序不一致的优化场景,最终我们和官方一起将方案进行了整合。该优化方案已经在 7.6 合并,大家可以试用体验。</p>
<p>前面从底层的存储模型到上层的执行引擎分别举例剖析了优化,实际上我们在性能层面还做了很多的优化。从底层的存储模型到执行引擎,到优化器,到上层的缓存策略基本都有覆盖。下图中左边是优化项,中间是优化效果,右边是有代表性的优化的 PR 列表。</p>
<p><img src="assets/es-tencent-y-17.jpeg" alt="img" /></p>
<p>这里简单再介绍一下其它的 PR 优化,中间这个 translog 刷新过程中锁的粗化优化能将整体写入性能提升 20%;这个 lucene 层面的文件裁剪优化,它能将带 id 写入场景性能提升一倍,当然查询也是,因为带 id 的写入需要先根据 id 查询文档是否存在,它的优化主要是在根据 id 准备遍历查询一个 segment 文件的时候,能快速根据这个 segment 所统计的最大最小值进行裁剪,如果不在范围则快速裁剪跳过,避免遍历文档;最下面的一个 PR 是缓存策略的优化,能避免一些开销比较大的缓存,大幅的降低查询毛刺。</p>
<p>上面这些性能优化项在我们腾讯云的 ES 版本中均有合入,大家可以试用体验。</p>
<h3>成本优化</h3>
<p>接下来我们再看成本优化。在日志、时序等大规模数据场景下,集群的 CPU、内存、磁盘的成本占比是 1 比 4 比 8。例如一般 16 核 64GB2-5 TB 磁盘节点的成本占比大概是这个比例。因此成本的主要瓶颈在于磁盘和内存。</p>
<p><img src="assets/es-tencent-y-18.jpeg" alt="img" /></p>
<p>成本优化的主要目标是存储成本和内存成本。</p>
<h4>存储成本</h4>
<p>我们先来看下存储成本。</p>
<p><img src="assets/es-tencent-y-19.jpeg" alt="img" /></p>
<p>我们先来看一个场景,整个腾讯云监控是基于 ES 的单个集群平均写入千万每秒业务需要保留至少半年的数据供查询。我们按照这个吞吐来计算成本1000 万 QPS 乘以时间乘以单条文档平均大小再乘以主从两个副本总共大约 14 PB 存储,大约需要 1500 台热机型物理机。这显然远远超出了业务成本预算,那我们如何才能既满足业务需求又能实现低成本呢?</p>
<p>来看下我们的优化方案,首先我们对业务数据访问频率进行调研,发现最近的数据访问频率较高,例如最近 5 分钟的,一小时的,一天的,几天的就比较少了,超过一个月的就更少了,历史数据偏向于统计分析。</p>
<p>首先我们可以通过冷热分离,把冷数据放到 HDD 来降低成本,同时利用官方提供的索引生命周期管理来搬迁数据,冷数据盘一般比较大我们还要利用多盘策略来提高吞吐和数据容灾能力。最后将超冷的数据冷备到腾讯云的对象存储 COS 上冷备成本非常低1GB 一个月才一毛多。</p>
<p>上面这些我们都可以从架构层面进行优化。是否还有其它优化点呢?基于前面分析的数据访问特征,历史数据偏向统计分析,我们提出了 Rollup 方案。Rollup 的目的是对历史数据降低精度,来大幅降低存储成本。我们通过预计算来释放原始细粒度的数据,例如秒级的数据聚合成小时级,小时级聚合成天级。这样对于用户查询时间较长的跨度报表方便展示,查询几天的秒级数据太细没法看。另外可以大幅降低存储成本,同时可以提升查询性能。</p>
<p>我们在 17 年的时候就实现了 Rollup 的方案并投入给了腾讯云监控使用,当然目前官方也出了 Rollup 方案,目前功能还在体验中。</p>
<p>下面介绍一下我们最新的 Rollup 方案的要点。</p>
<p><img src="assets/es-tencent-y-20.jpeg" alt="img" /></p>
<p>总体来说 Rollup 优化方案主要是基于流式聚合加查询剪枝结合分片级并发来实现其高效性。流式聚合和查询剪枝的优化我们前面在性能优化部分已经介绍了,我们新的 Rollup 也利用了这些优化,这里不再展开。下面介绍一下分片级并发,及并发自动控制策略。</p>
<p>正常的聚合查询,需要将请求发送给每个分片进行子聚合,在到协调节点做汇聚,两次聚合多路归并。我们通过给数据添加 routing 的方式让相同的对象落到相同的分片内,这样就只需要一层聚合,因为分片数据独立,多个数据对象可以实现分片级并发。 另外我们通过对 Rollup 任务资源预估,并感知集群的负载压力来自动控制并发度,这样对集群整体的影响能控制在一定的范围。右边的图是我们的优化效果,某个统计指标 30 天的存储量,天级的只需要 13 GB小时级的只需要 250 GB细粒度的会多一些总体存储量下降了将近 10 倍。单个集群 150 台左右物理机即可搞定,成本缩减 10 倍。整体写入开销 rollup 资源消耗在 10% 以下。</p>
<h4>内存成本优化</h4>
<p>前面是存储成本优化,下面介绍内存成本优化。</p>
<p><img src="assets/es-tencent-y-21.jpeg" alt="img" /></p>
<p>我们通过对线上集群进行分析,发现很多场景堆内内存使用率很高,而磁盘的使用率比较低。堆内存使用率为什么这么高呢?其中的 FST 即倒排索引占据了绝大部分堆内内存,而且这部分是常驻内存的。每 10 TB 的磁盘 FST 的内存消耗大概在 10 GB 到 15 GB 左右。</p>
<p>我们能不能对 FST 这种堆内占用比较大的内存做优化我们的想法是把它移至堆外off-heap按需加载提升堆内内存利用率降低 GC 开销,提升单个节点管理磁盘的能力。</p>
<p><img src="assets/es-tencent-y-22.jpeg" alt="img" /></p>
<p>我们来看下 off-heap 相关的方案。首先原生版本目前也实现了 off-heap方案是将 FST 对象放到 MMAP 中管理,这种方式实现简单,我们早期也采用了这种方式实现,但是由于 MMAP 属于 page cache 可能被系统回收掉,导致读盘操作,从而带来性能的 N 倍损耗,容易产生查询毛刺。</p>
<p>HBase 2.0 版本中也实现了 off-heap在堆外建立了 cache脱离系统缓存但只是把数据放到堆外索引仍然在堆内而且淘汰策略完全依赖 LRU 策略,冷数据不能及时的清理。</p>
<p>我们的优化方案也是在堆外建立 cache保证 FST 的空间不受系统影响,另外我们会实现更精准的淘汰策略,提高内存使用率,再加上多级 cache 的管理模式来提升性能。这种方式实现起来比较复杂但收益还是很明显的,下面我们来看一下详细的实现。</p>
<p><img src="assets/es-tencent-y-23.jpeg" alt="img" /></p>
<p>我们的方案是通过 LRU cache + 零拷贝 + 两级 cache 的方式实现的。首先 LRU cache 是建立在堆外,堆内有访问 FST 需求的时候从磁盘加载到 cache 中。由于 Lucene 默认的访问 FST 的方式是一个堆内的 buffer前期我们采用了直接从堆外拷贝到堆内的 buffer 方式实现,压测发现查询性能损耗 20%,主要是堆外向堆内 copy 占了大头。</p>
<p>因此我们有了第二阶段优化,将 Lucene 访问 FST 的方式进行了改造buffer 里面不直接存放 FST而存放堆外对象的一个指针这样实现了堆内和堆外之间的零拷贝这里的零拷贝和我们说的 linux 中的用户态和内核态的零拷贝是两个概念。这样实现后我们压测发现查询性能还是有 7%的损耗,相较于堆内的 FST 场景。我们有没办法做到极致呢?</p>
<p>我们通过分析发现,这 7% 的损耗主要是根据 key 去查找堆外对象的过程,包括计算 hash数据校验等。我们第三阶段的优化就是利用 Java 的弱引用建立第二层轻量级缓存。弱引用指向堆外的地址,只要有请求使用,这个 key 就不会被回收可以重复利用而无需重新获取。一旦不在使用,这个 key 就会被 GC 回收掉,并回收掉堆外对象指针。问题来了,堆外对象指针回收之后我们怎么清理堆外这部分内存呢?让其 LRU 淘汰?这样显然会浪费一部分内存空间。最好的办法是在堆内对象地址回收的时候直接回收堆外对象,但是 Java 没有析构的概念。这里我们利用了弱引用的 Reference Queue当对象要被 GC 回收的时候会将对象指向的堆外内存清理掉,这样完美解决了堆外内存析构的问题,保证了堆外内存的精准淘汰,提升内存利用率。最后通过压测我们发现性能基本和原生方案 FST 在堆内的场景持平。</p>
<p>下面是内存优化相关的效果和收益:</p>
<p><img src="assets/es-tencent-y-24.jpeg" alt="img" /></p>
<p>通过我们的内存优化后内存开销、数据管理能力、GC 优势明显,性能持平略有优势。单个 FST 堆内占用只需要 100 个 byte 左右即 cache key 的大小。单节点磁盘管理能力32GB heap 能到 50 TB 左右,相较原生版本 5-10 TB需要深度调优有 10 倍的提升。利用官方提供的 esrally 进行性能压测发现堆内存使用量有大幅的下降GC 时长也有缩减,性能基本持平。</p>
<h3>扩展性优化</h3>
<p>接下来是最后一块内核优化内容,<strong>扩展性优化</strong></p>
<p><img src="assets/es-tencent-y-25.jpeg" alt="img" /></p>
<p>我们先来看一下场景。ES 的元数据管理模型是master 管理元数据,其它所有节点同步元数据。我们以建索引流程为例,来看看元数据的同步流程。首先是 master 分配分片,然后产生 diff 的元数据,发送给其它节点,等待大多数 master 节点返回master 发送元数据应用请求,其它节点开始应用元数据,并根据新旧元数据推导出各自节点的分片创建任务。</p>
<p>这里面的瓶颈点主要有以下几点:</p>
<ul>
<li>Mater 节点在分配分片的时候,需要做一遍元数据的正反向转换。我们知道路由信息是由分片到节点的映射,而我们在做分片分配的时候需要节点到分片的映射,需要知道每个节点上的分片分布。分片分配完毕又需要将节点到分片的映射转换回来,因为我们元数据只发布分片到节点的映射。这个转换过程涉及多次的全量遍历,大规模分片性能存在瓶颈。</li>
<li>在每次索引创建的过程中,会涉及多次的元数据同步,在大规模的节点数场景,会出现同步瓶颈,上千节点,部分节点假设有一点网络抖动或 Old GC 可能导致同步失败。</li>
</ul>
<p>基于上面的瓶颈,目前原生版本只能支持大约 3-5 万分片,性能已经到达极限,创建索引基本到达 30 秒+ 甚至分钟级。节点数只能到 500 左右基本是极限了。</p>
<p>为此,我们提出了扩展性优化方案。</p>
<p><img src="assets/es-tencent-y-26.jpeg" alt="img" /></p>
<p>主要的优化内容包括:</p>
<ul>
<li><strong>分片创建任务式定向下发</strong> 对于创建分片导致的元数据同步瓶颈,我们采用任务下发的方式,定向下发分片创建任务,避免多次全节点元数据同步。</li>
<li><strong>元数据增量维护</strong> 分配分片的过程中多次正反向遍历,我们采用增量化的数据结构维护的方式,避免全量的遍历。</li>
<li><strong>统计缓存策略</strong> 统计接口的性能,我们采用缓存策略避免多次重复的统计计算,大幅降低资源开销。 最终我们将集群的分片数扩展到百万级,节点数扩展到千级,新建索引基本稳定在 5 秒以下,统计接口秒级响应。</li>
</ul>
<p>前面就是所有的内核优化的内容。ES 是一款很优秀的开源大数据产品,我们将持续的建设。我们对公司内外提供了完整的托管平台,对 ES 内核各个层面做了系统性的增强优化,助力 Elastic Stack 在大数据生态中覆盖更多的场景,发展的更好。</p>
<p><img src="assets/es-tencent-y-27.jpeg" alt="img" /></p>
<h2>四、开源贡献及未来规划</h2>
<p><img src="assets/es-tencent-y-28.jpeg" alt="img" /></p>
<p>在腾讯内部,我们实现了 ES 产品开源协同,共同优化完善 ES避免不同的团队重复踩坑。同时我们也将优秀的方案积极的贡献给社区和官方及社区的 ES 爱好者们共同推动 ES 的发展。以腾讯 ES 内核研发为代表的团队,截至目前我们共提交了二十多个 PR其中有 70% 被合并,共有 6 位 ES/Lucene 的 contributor。</p>
<p>未来,我们将持续的优化 ES包括可用性性能和成本等方面。可用性方面我们会加强 ES 的故障自愈能力,朝着自动驾驶的目标发展;性能方面,搜索场景 ES 是绝对的王者,多维分析领域还有很多可优化的地方,我们希望能进一步扩展 ES 在分析领域的应用场景。成本方面,存储与计算分离正在研发中,基于腾讯自研的共享文件系统 CFS到时会进一步缩减成本提升性能。</p>
<h2>资源链接</h2>
<p>线上 PPT 的链接https://elasticsearch.cn/slides/259</p>
<p>分享过程中相关问题的答疑https://elasticsearch.cn/articl</p>
<p>腾讯Elasticsearch海量规模背后的内核优化剖析 https://zhuanlan.zhihu.com/p/139725905</p>
<p>腾讯万亿级 Elasticsearch 内存效率提升技术解密 https://zhuanlan.zhihu.com/p/146083622</p>
<p>腾讯万亿级 Elasticsearch 技术解密 https://zhuanlan.zhihu.com/p/99184436</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996fb419063d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,728 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>20 WrapperQuery.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>20 WrapperQuery</h1>
<h2>实现方式理论基础</h2>
<ul>
<li>Wrapper Query 官网说明</li>
</ul>
<p>https://www.elastic.co/guide/en/elasticsearch/reference/6.4/query-dsl-wrapper-query.html</p>
<blockquote>
<p>This query is more useful in the context of the Java high-level REST client or transport client to also accept queries as json formatted string. In these cases queries can be specified as a json or yaml formatted string or as a query builder (which is a available in the Java high-level REST client).</p>
</blockquote>
<pre><code class="language-json">GET /_search
{
&quot;query&quot; : {
&quot;wrapper&quot;: {
&quot;query&quot; : &quot;eyJ0ZXJtIiA6IHsgInVzZXIiIDogIktpbWNoeSIgfX0=&quot; // Base64 encoded string: {&quot;term&quot; : { &quot;user&quot; : &quot;Kimchy&quot; }}
}
}
}
</code></pre>
<ul>
<li>将DSL JSON语句 转成 map</li>
</ul>
<p>https://blog.csdn.net/qq_41370896/article/details/83658948</p>
<pre><code class="language-java">String dsl = &quot;&quot;;
Map maps = (Map)JSON.parse(dsl);
maps.get(&quot;query&quot;);// dsl query string
</code></pre>
<ul>
<li>Java 代码</li>
</ul>
<p>https://blog.csdn.net/tcyzhyx/article/details/84566734</p>
<p>https://www.jianshu.com/p/216ca70d9e62</p>
<pre><code class="language-java">StringBuffer dsl = new StringBuffer();
dsl.append(&quot;{\&quot;bool\&quot;: {&quot;);
dsl.append(&quot; \&quot;must\&quot;: [&quot;);
dsl.append(&quot; {&quot;);
dsl.append(&quot; \&quot;term\&quot;: {&quot;);
dsl.append(&quot; \&quot;mdid.keyword\&quot;: {&quot;);
dsl.append(&quot; \&quot;value\&quot;: \&quot;2fa9d41e1af460e0d47ce36ca8a98737\&quot;&quot;);
dsl.append(&quot; }&quot;);
dsl.append(&quot; }&quot;);
dsl.append(&quot; }&quot;);
dsl.append(&quot; ]&quot;);
dsl.append(&quot; }&quot;);
dsl.append(&quot;}&quot;);
WrapperQueryBuilder wqb = QueryBuilders.wrapperQuery(dsl.toString());
SearchResponse searchResponse = client.prepareSearch(basicsysCodeManager.getYjzxYjxxIndex())
.setTypes(basicsysCodeManager.getYjzxYjxxType()).setQuery(wqb).setSize(10).get();
SearchHit[] hits = searchResponse.getHits().getHits();
for(SearchHit hit : hits){
String content = hit.getSourceAsString();
System.out.println(content);
}
</code></pre>
<ul>
<li>query + agg 应该怎么写</li>
</ul>
<p>http://www.itkeyword.com/doc/1009692843717298639/wrapperquerybuilder-aggs-query-throwing-query-malformed-exception</p>
<pre><code class="language-json">&quot;{\&quot;query\&quot;:{\&quot;match_all\&quot;: {}},\&quot;aggs\&quot;:{\&quot;avg1\&quot;:{\&quot;avg\&quot;:{\&quot;field\&quot;:\&quot;age\&quot;}}}}&quot;
SearchSourceBuilder ssb = new SearchSourceBuilder();
// add the query part
String query =&quot;{\&quot;match_all\&quot;: {}}&quot;;
WrapperQueryBuilder wrapQB = new WrapperQueryBuilder(query);
ssb.query(wrapQB);
// add the aggregation part
AvgBuilder avgAgg = AggregationBuilders.avg(&quot;avg1&quot;).field(&quot;age&quot;);
ssb.aggregation(avgAgg);
</code></pre>
<h2>实现示例</h2>
<p></p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996fb93c533d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

View File

@@ -0,0 +1,774 @@
<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>21 备份和迁移.md</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/ElasticSearch知识体系详解/01 认知ElasticSearch基础概念.md">01 认知ElasticSearch基础概念.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/02 认知Elastic Stack生态和场景方案.md">02 认知Elastic Stack生态和场景方案.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/03 安装ElasticSearch和Kibana安装.md">03 安装ElasticSearch和Kibana安装.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/04 入门:查询和聚合的基础使用.md">04 入门:查询和聚合的基础使用.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/05 索引:索引管理详解.md">05 索引:索引管理详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/06 索引:索引模板(Index Template)详解.md">06 索引:索引模板(Index Template)详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/07 查询DSL查询之复合查询详解.md">07 查询DSL查询之复合查询详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/08 查询DSL查询之全文搜索详解.md">08 查询DSL查询之全文搜索详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/09 查询DSL查询之Term详解.md">09 查询DSL查询之Term详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/10 聚合聚合查询之Bucket聚合详解.md">10 聚合聚合查询之Bucket聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/11 聚合聚合查询之Metric聚合详解.md">11 聚合聚合查询之Metric聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/12 聚合聚合查询之Pipline聚合详解.md">12 聚合聚合查询之Pipline聚合详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/13 原理从图解构筑对ES原理的初步认知.md">13 原理从图解构筑对ES原理的初步认知.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/14 原理ES原理知识点补充和整体结构.md">14 原理ES原理知识点补充和整体结构.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/15 原理ES原理之索引文档流程详解.md">15 原理ES原理之索引文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/16 原理ES原理之读取文档流程详解.md">16 原理ES原理之读取文档流程详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/17 优化ElasticSearch性能优化详解.md">17 优化ElasticSearch性能优化详解.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md">18 大厂实践:腾讯万亿级 Elasticsearch 技术实践.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/19 资料Awesome Elasticsearch.md">19 资料Awesome Elasticsearch.md.html</a>
</li>
<li>
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">20 WrapperQuery.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/ElasticSearch知识体系详解/21 备份和迁移.md">21 备份和迁移.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>21 备份和迁移</h1>
<h2>方案</h2>
<h3>离线方案</h3>
<ul>
<li>Snapshot</li>
<li>Reindex</li>
<li>Logstash</li>
<li>ElasticSearch-dump</li>
<li>ElasticSearch-Exporter</li>
</ul>
<h3>增量备份方案</h3>
<ul>
<li>logstash</li>
</ul>
<h2>使用快照进行备份</h2>
<h3>配置信息</h3>
<p>注册前要注意配置文件加上: elasticsearch.yml</p>
<pre><code class="language-bash">path.repo: [&quot;/opt/elasticsearch/backup&quot;]
</code></pre>
<h3>创建仓库</h3>
<blockquote>
<p>注册一个仓库,存放快照,记住,这里不是生成快照,只是注册一个仓库</p>
</blockquote>
<pre><code class="language-bash">curl -XPUT 'http://10.11.60.5:9200/_snapshot/repo_backup_1' -H 'Content-Type: application/json' -d '{
&quot;type&quot;: &quot;fs&quot;,
&quot;settings&quot;: {
&quot;location&quot;: &quot;/opt/elasticsearch/backup&quot;,
&quot;max_snapshot_bytes_per_sec&quot;: &quot;20mb&quot;,
&quot;max_restore_bytes_per_sec&quot;: &quot;20mb&quot;,
&quot;compress&quot;: true
}
}'
</code></pre>
<p>查看仓库信息:</p>
<pre><code class="language-bash">curl -XGET 'http://10.11.60.5:9200/_snapshot/repo_backup_1?pretty'
</code></pre>
<p>返回内容</p>
<pre><code class="language-bash">[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="64160b0b102437302b36492137">[email&#160;protected]</a> elasticsearch]# curl -XGET 'http://10.11.60.5:9200/_snapshot/repo_backup_1?pretty'
{
&quot;repo_backup_1&quot; : {
&quot;type&quot; : &quot;fs&quot;,
&quot;settings&quot; : {
&quot;location&quot; : &quot;/opt/elasticsearch/backup&quot;,
&quot;max_restore_bytes_per_sec&quot; : &quot;20mb&quot;,
&quot;compress&quot; : &quot;true&quot;,
&quot;max_snapshot_bytes_per_sec&quot; : &quot;20mb&quot;
}
}
}
</code></pre>
<h3>创建快照</h3>
<pre><code class="language-bash">curl -XPUT 'http://10.11.60.5:9200/_snapshot/repo_backup_1/snapshot_1?wait_for_completion=true&amp;pretty' -H 'Content-Type: application/json' -d '{
&quot;indices&quot;: &quot;bro-2019-09-14,bro-2019-09-15,wmi-2019-09-14,wmi-2019-09-15,syslog-2019-09-14,sylog-2019-09-15&quot;,
&quot;rename_pattern&quot;: &quot;bro_(.+)&quot;,
&quot;rename_replacement&quot;: &quot;dev_bro_$1&quot;,
&quot;ignore_unavailable&quot;: true,
&quot;include_global_state&quot;: true
}'
</code></pre>
<p>执行</p>
<pre><code class="language-bash">{
&quot;snapshot&quot; : {
&quot;snapshot&quot; : &quot;snapshot_1&quot;,
&quot;version_id&quot; : 2040399,
&quot;version&quot; : &quot;2.4.3&quot;,
&quot;indices&quot; : [ &quot;bro-2019-09-14&quot;, &quot;bro-2019-09-15&quot;, &quot;wmi-2019-09-15&quot;, &quot;syslog-2019-09-14&quot;, &quot;wmi-2019-09-14&quot; ],
&quot;state&quot; : &quot;SUCCESS&quot;,
&quot;start_time&quot; : &quot;2019-09-18T05:58:08.860Z&quot;,
&quot;start_time_in_millis&quot; : 1568786288860,
&quot;end_time&quot; : &quot;2019-09-18T06:02:18.037Z&quot;,
&quot;end_time_in_millis&quot; : 1568786538037,
&quot;duration_in_millis&quot; : 249177,
&quot;failures&quot; : [ ],
&quot;shards&quot; : {
&quot;total&quot; : 25,
&quot;failed&quot; : 0,
&quot;successful&quot; : 25
}
}
}
</code></pre>
<h3>恢复数据</h3>
<h2>方案使用场景</h2>
<h2>迁移考虑的问题</h2>
<ul>
<li>版本问题,从低版本到高版本数据的迁移</li>
<li>多租户的适配问题</li>
</ul>
<blockquote>
<p>多个工厂的数据进入不同index, 原有的数据bro-2019-09-15的数据需要进入factorycode-bro-2019-09-15</p>
</blockquote>
<ul>
<li>多次或者分批迁移数据</li>
<li>数据在迁移时候富化</li>
<li>FieldMapping 和 数据信息 分离?</li>
</ul>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/ElasticSearch知识体系详解/20 WrapperQuery.md">上一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70996fbb59103d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Some files were not shown because too many files have changed in this diff Show More