<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>易博云天 &#187; Elasticsearch</title>
	<atom:link href="http://www.eavea.com/blog/index.php/tag/elasticsearch/feed" rel="self" type="application/rss+xml" />
	<link>http://www.eavea.com/blog</link>
	<description>专注技术：学习、交流、分享、免费，每天进步一点点！</description>
	<lastBuildDate>Mon, 13 Mar 2023 07:04:16 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6.1</generator>
		<item>
		<title>Elasticsearch Query DSL入门</title>
		<link>http://www.eavea.com/blog/index.php/elasticsearchquerydslrumen.html</link>
		<comments>http://www.eavea.com/blog/index.php/elasticsearchquerydslrumen.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:58:54 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[后端技术]]></category>
		<category><![CDATA[Elasticsearch]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=67</guid>
		<description><![CDATA[Elasticsearch Query DSL入门 列举几个最基础的 DSL 语句，所有长达成百上千行的 DS [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>Elasticsearch Query DSL入门</div>
<blockquote><p>列举几个最基础的 DSL 语句，所有长达成百上千行的 DSL 都是由这些基础语法组合起来的。</p></blockquote>
<h2 id="toc-heading-1">一、环境</h2>
<ul>
<li>Ubuntu 14.04/16、04</li>
<li>JDK1.8</li>
<li>Elasticsearch 5.3</li>
<li>Kibana 5.3.2</li>
</ul>
<h2 id="toc-heading-2">二、DSL介绍</h2>
<p>Query DSL 又叫查询表达式，是一种非常灵活又富有表现力的查询语言，采用 JSON 接口的方式实现丰富的查询，并使你的查询语句更灵活、更精确、更易读且易调试。</p>
<p>我平时喜欢借助 Kibana 来执行 DSL 语句，它能够辅助自己开发，也能用于 debug 和研究。</p>
<p>实际项目中一般封装一下第三方引擎来实现业务，而这些语法转换成 DSL 后经常有成百上千行，但其实一点也不复杂。不管是过滤、聚合还是嵌套，只要理解了最基本的语法，都是很好解读的。</p>
<p>这篇文章主要还是记录下我平时常用的几个 DSL，防止隔得时间久了，裸写 DSL 不一定写得出来。</p>
<h2 id="toc-heading-3">三、全文查询</h2>
<h3 id="toc-heading-4">1. match_all</h3>
<p>/_search 查找整个ES中所有索引的内容，/ 前面可以加上索引名，多个索引名之前用英文逗号分割。<br />
下面这个语法是 match_all 查询，Kibana 能够自动补全代码，最简单。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /_search
{
  "query": {
    "match_all": {}
  }
}
</code></pre>
<h3 id="toc-heading-5">2. match</h3>
<p>下边的例子就表示查找 host 为 wenyuanblog.com 的所有记录。</p>
<div>bash<i></i><i></i></div>
<pre><code>POST /wenyuanblog-2018.03.02/_search
{
  "query": {
    "match": {
      "host": "wenyuanblog.com"
    }
  }
}
</code></pre>
<h3 id="toc-heading-6">3. multi_match</h3>
<p>在多个字段上执行相同的 match 查询，下边的例子就表示查询 host 或 http_referer 字段中包含 wenyuanblog.com 的记录。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "multi_match": {
      "query": "wenyuanblog.com",
      "fields": [
        "host",
        "http_referer"
      ]
    }
  }
}
</code></pre>
<h3 id="toc-heading-7">4. query_string</h3>
<p>可以在查询里边使用 AND 或者 OR 来完成复杂的查询。</p>
<p>下边的例子表示查找 host 为 a.wenyuanblog.com 或者 b.wenyuanblog.com 的所有记录。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "query_string": {
      "query": "(a.wenyuanblog.com) OR (b.wenyuanblog.com)",
      "fields": [
        "host"
      ]
    }
  }
}
</code></pre>
<p>也可以组合更多的条件完成更复杂的查询请求。</p>
<p>下边的例子表示查询（host 为 a.wenyuanblog.com）或者是（host 为 b.wenyuanblog.com 且 status 为 404）的所有记录。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "query_string": {
      "query": "host:a.wenyuanblog.com OR (host:b.wenyuanblog.com AND status:404)"
    }
  }
}
</code></pre>
<p>与其相类似的还有个 simple_query_string 的关键字，可以将 query_string 中的 AND 或 OR 用 + 或 | 这样的符号替换掉。</p>
<h3 id="toc-heading-8">5. term</h3>
<p>term 可以用来精确匹配，精确匹配的值可以是数字、时间、布尔值或者是设置了 not_analyzed 不分词的字符串。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "term": {
      "status": {
        "value": 404
      }
    }
  }
}
</code></pre>
<p>term 对输入的文本不进行分析，直接精确匹配输出结果，如果要同时匹配多个值可以使用 terms。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "terms": {
      "status": [
        403,
        404
      ]
    }
  }
}
</code></pre>
<h3 id="toc-heading-9">6. range</h3>
<p>range 用来查询落在指定区间内的数字或者时间。<br />
下边的例子表示搜索所有状态为 200 到 399 之间的数据，这里的操作符主要有四个 gt 大于，gte 大于等于，lt 小于，lte 小于等于。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "range": {
      "status": {
        "gte": 200,
        "lte": 399
      }
    }
  }
}
</code></pre>
<p>当使用日期作为范围查询时，我们需要注意下日期的格式，官方支持的日期格式主要有两种：</p>
<p>① 时间戳，注意是毫秒粒度。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "range": {
      "@timestamp": {
        "gte": 1519920000000,
        "lte": 1519956000000,
        "format": "epoch_millis"
      }
    }
  }
}
</code></pre>
<p>② 日期字符串。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "range": {
      "@timestamp": {
        "gte": "2018-03-02 00:00:00",
        "lte": "2018-03-03",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd",
        "time_zone": "+08:00"
      }
    }
  }
}
</code></pre>
<p>选择哪种方式根据实际情况决定，我们业务中用时间戳的情况居多。</p>
<p>如果采用日期字符串的方式，那么可以使用 format 字段指定匹配的日期格式，如果格式有多个就用 || 分开，像例子中那样，不过建议用同样的日期格式。</p>
<p>如果日期中缺少年月日这些内容，那么缺少的部分会用 unix 的开始时间（即 1970年1月1日）填充，当你将 “format”:”dd” 指定为格式时，那么 “gte”:10 将被转换成 1970-01-10T00:00:00.000Z。</p>
<p>Elasticsearch 中默认使用的是 UTC 时间，所以我们在使用时要通过 time_zone 来设置好时区，以免出错。</p>
<h3 id="toc-heading-10">7. exists</h3>
<p>查询出存在某字段的文档。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "exists": {
            "field": "visitor.name"
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 100
}
</code></pre>
<h3 id="toc-heading-11">8. bool组合查询</h3>
<p>通常我们可能需要将很多个条件组合在一起查出最后的结果，这个时候就需要使用 ES 提供的 bool 来实现了。<br />
布尔查询支持的子查询类型共有四种，分别是：must，should，must_not 和 filter。</p>
<p>must：类似于 SQL 中的 AND ，必须包含；<br />
must_not：类似于 SQL 中的 NOT，必须不包含；<br />
should：文档应该匹配 should 子句查询的一个或多个；<br />
filter：过滤器，文档必须匹配该过滤条件，跟 must 子句的唯一区别是，filter 不会对结果进行相关性评分 _score，换言之当我们的业务中无相关性的要求时，建议查询的过程中多用 filter。</p>
<p>下面是一个组合查询的例子，我们要查询 host 为 wenyuanblog.com 且 http_x_forworded_for 为 47.97.12.69 且 status 不为 200 的所有数据。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
            "host": "wenyuanblog.com"
          }
        },
        {
          "match": {
            "http_x_forwarded_for": "47.97.12.69"
          }
        }
      ],
      "must_not": {
        "match": {
          "status": 200
        }
      }
    }
  }
}
</code></pre>
<p>这里再说一下 should。通常情况下，should 子句是数组字段，包含多个 should 子查询，默认情况下，匹配的文档必须满足其中一个子查询条件。</p>
<p>但我们可以通过显式设置布尔查询的参数 minimum_should_match 的值，从而改变默认匹配行为。该参数控制一个文档必须匹配的 should 子查询的数量，它有很多种配置方式：</p>
<p>如果设置为数字 3，表示至少需要匹配 3 个 should 子句；如果设置为一个百分比，例如 “minimum_should_match”:75%，则至少满足 75% 且向下取整（5个 should 子句，5*75%=3.75，向下取整为 3，也就是至少匹配 3 个 should 子句）。</p>
<p>下面是个例子。（注：在 bool query 中 minimum_should_match 只能紧跟在 should 的后面，放其他地方会出异常）</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "host": "a.wenyuanblog.com"
          }
        },
        {
          "match": {
            "host": "b.wenyuanblog.com"
          }
        },
        {
          "match": {
            "host": "c.wenyuanblog.com"
          }
        }
      ],
      "minimum_should_match": 2
    }
  }
}
</code></pre>
<h3 id="toc-heading-12">9. sort</h3>
<p>sort 是排序，也是很常用的查询，这里我举个按时间（@timestamp）倒叙查询的例子。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "@timestamp": {
        "order": "desc"
      }
    }
  ]
}
</code></pre>
<h2 id="toc-heading-13">四、聚合查询</h2>
<h3 id="toc-heading-14">1. 分桶</h3>
<p>根据 host 字段的值进行分桶（有点类似于 SQL 中的 group by），这里的 host_bucket 是我给该桶起的名字。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "host_bucket": {
      "terms": {
        "field": "host"
      }
    }
  }
}
</code></pre>
<h3 id="toc-heading-15">2. 度量</h3>
<p>计算出 latency 字段的最大值（metric 有点类似于 SQL 的 avg、max、min），这里的 max_latency 是我给该度量起的名字。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2018.03.02/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "max_latency": {
      "max": {
        "field": "latency"
      }
    }
  }
}
</code></pre>
<h2 id="toc-heading-16">五、业务应用</h2>
<p>实际业务中的一些需求，属于较综合的查询语法。</p>
<h3 id="toc-heading-17">1. 聚合结果进行排序</h3>
<p>关键词：aggregations，terms，order。</p>
<p>先过滤出 host 字段值为 “wenyuanblog.com” 的记录，然后对 源IP 进行分桶聚合，最后根据聚合查询到的 文档数量倒序排序。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2019.05.*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "@timestamp": {
              "to": 1557503999000,
              "from": 1557417600000
            }
          }
        },
        {
          "term": {
            "host": "wenyuanblog.com"
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 0,
  "aggregations": {
    "src_ip_bucket": {
      "terms": {
        "field": "http.src_ip.dotted",
        "size": 10,
        "order": {
          "_count": "desc"
        }
      }
    }
  }
}
</code></pre>
<h3 id="toc-heading-18">2. IP范围过滤+分桶+度量+脚本+排序</h3>
<p>关键词：range，aggregations，terms，metric，script，order。</p>
<p>先根据 IP范围 过滤，同时排除指定 host；<br />
接着对 源IP 进行分桶聚合，再计算 进流量、出流量 在该时间段内的总和，用脚本计算出 总流量（进流量+出流量） ，最后根据 总流量（进流量+出流量） 数值大小进行倒序排序。</p>
<p>使用groovy：</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2019.05.*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "bool": {
            "must": [
              {
                "range": {
                  "@timestamp": {
                    "to": 1557503999000,
                    "from": 1557417600000
                  }
                }
              },
              {
                "range": {
                  "http.src_ip.dotted": {
                    "to": "10.255.255.255",
                    "from": "10.0.0.0"
                  }
                }
              },
              {
                "bool": {
                  "must_not": [
                    {
                      "terms": {
                        "host": [
                          "a.wenyuanblog.com",
                          "b.wenyuanblog.com"
                        ]
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 0,
  "aggs": {
    "appid_bucket": {
      "terms": {
        "field": "http.src_ip.dotted",
        "order": {
          "sum_total_bytes": "desc"
        },
        "size": 100
      },
      "aggs": {
        "sum_in_bytes": {
          "sum": {
            "field": "http.in_bytes"
          }
        },
        "sum_out_bytes": {
          "sum": {
            "field": "http.out_bytes"
          }
        },
        "sum_total_bytes": {
          "sum": {
            "script": {
              "lang": "groovy",
              "inline": "doc['http.in_bytes'].value + doc['http.out_bytes'].value"
            }
          }
        }
      }
    }
  }
}
</code></pre>
<p>使用 painless，修改 script 部分如下：</p>
<div>bash<i></i><i></i></div>
<pre><code>"sum_total_bytes": {
  "sum": {
    "script": {
      "lang": "painless",
      "inline": "doc['tcp.in_bytes'].value + doc['tcp.out_bytes'].value"
    }
  }
}
</code></pre>
<p>以前一直用 groovy，因为比较好用。但最近两年的某个版本开始将其 Deprecation 了，官方推荐使用 painless。<br />
painless 也能实现一些脚本语法，具体可以上官网查询。</p>
<h3 id="toc-heading-19">3. IP范围过滤+聚合过滤+度量</h3>
<p>关键词：range，aggregations，filter，metric。</p>
<p>先根据 IP范围 过滤，然后开始聚合，筛选出 目的端口 是 80、443 的数据，再计算这些数据中（80、443端口） 进流量、出流量 在该时间段内的总和。</p>
<p>至于为什么要在聚合中进行过滤而不是在聚合前就过滤，是因为下面语句只是完整 dsl 的一部分，该查询业务还要同时对其它端口进行聚合操作。</p>
<div>bash<i></i><i></i></div>
<pre><code>GET /wenyuanblog-2019.05.*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "bool": {
            "must": [
              {
                "range": {
                  "@timestamp": {
                    "to": 1557503999000,
                    "from": 1557417600000
                  }
                }
              },
              {
                "range": {
                  "http.src_ip.dotted": {
                    "to": "10.255.255.255",
                    "from": "10.0.0.0"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 0,
  "aggs": {
    "dport_80_443": {
      "filter": {
        "bool": {
          "must": [
            {
              "terms": {
                "http.dport": [
                  80,
                  443
                ]
              }
            }
          ]
        }
      },
      "aggs": {
        "sum_in_bytes": {
          "sum": {
            "field": "http.in_bytes"
          }
        },
        "sum_out_bytes": {
          "sum": {
            "field": "http.out_bytes"
          }
        }
      }
    }
  }
}
</code></pre>
<h2 id="toc-heading-20">六、总结</h2>
<p>ES 很强大，它支持的查询有很多，这里我只是列举了平时在 Kibana 中经常调试的 DSL。</p>
<p>还有很多实际业务中经常用到的模糊查询（wildcard、regexp、prefix）、nested 查询、多层聚合等等，基本上都是先封装第三方引擎，然后开发时转成 DSL 并 copy 到 Kibana 进行验证和查错。</p>
<p>更复杂的应用这里就不列举出来了，必要时候官方文档是最好的资料。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/elasticsearchquerydslrumen.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Elasticsearch索引备份与迁移</title>
		<link>http://www.eavea.com/blog/index.php/elasticsearchsuoyinbeifenyuqianyi.html</link>
		<comments>http://www.eavea.com/blog/index.php/elasticsearchsuoyinbeifenyuqianyi.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:57:23 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[运维知识]]></category>
		<category><![CDATA[Elasticsearch]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=66</guid>
		<description><![CDATA[Elasticsearch索引备份与迁移 总结Elasticsearch各种备份与迁移方案，亲测。 详细记录了 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>Elasticsearch索引备份与迁移</div>
<blockquote><p>总结Elasticsearch各种备份与迁移方案，亲测。<br />
详细记录了具体步骤。</p></blockquote>
<h2 id="toc-heading-1">一、环境</h2>
<ul>
<li>Ubuntu 14.04/16、04</li>
<li>JDK1.8</li>
<li>Elasticsearch 5.3</li>
<li>Kibana 5.3.2</li>
</ul>
<h2 id="toc-heading-2">二、单节点环境</h2>
<h3 id="toc-heading-3">1. 创建备份存储目录</h3>
<div>bash<i></i><i></i></div>
<pre><code>sudo mkdir /media/es/es_backup
# 该目录要是elasticsearch可访问的，我们的环境一般是elasticsearch用户
chown -R elasticsearch:elasticsearch /media/es/es_backup/
</code></pre>
<h3 id="toc-heading-4">2. 修改elasticsearch.yml文件</h3>
<p>修改 elasticsearch.yml 文件，添加 path.repo 配置。</p>
<div>bash<i></i><i></i></div>
<pre><code>vim elasticsearch.yml
# 增加一行如下：
path.repo: ["/media/es/es_backup"]
</code></pre>
<h3 id="toc-heading-5">3. 重启Elasticsearch</h3>
<h3 id="toc-heading-6">4. 创建仓库</h3>
<p>借助 Kibana 操作。</p>
<div>bash<i></i><i></i></div>
<pre><code># 创建仓库，创建一个名为my_backup的仓库
PUT _snapshot/my_backup
{
  "type": "fs",
  "settings": {
    "location": "/media/es/es_backup",
    "compress": true
  }
}

# 检查仓库是否创建成功（my_backup为之前创建的仓库名称） 
GET _snapshot/my_backup

# 删除仓库
DELETE _snapshot/my_backup
</code></pre>
<h3 id="toc-heading-7">5. 备份索引数据</h3>
<div>bash<i></i><i></i></div>
<pre><code># 给所有索引创建快照
PUT _snapshot/my_backup/snapshot_name        

# 针对具体的index创建快照备份
# 其中my_backup是仓库名称，snapshot_name是快照的名字
# ignore_unavailable在创建快照的过程中会忽略不存在的索引，默认情况下，如果没有设置，在索引不存在的情况下快照请求将会失败
# include_global_state能够防止集群的全局状态被作为快照的一部分存储起来
# 多个索引间不要加空格，否则只会对第一个索引操作（我踩过坑！！！）
PUT _snapshot/my_backup/snapshot_name?wait_for_completion=true
{
  "indices": "index_1,index_2",
  "ignore_unavailable": true,
  "include_global_state": false
}

# 查看指定仓库下所有快照
GET _snapshot/my_backup/_all

# 查看具体某一个快照的信息
GET _snapshot/my_backup/snapshot_name/_status

# 删除快照，要指定仓库名和快照名
# 也能用于取消一个正在进行的快照创建过程，会删除备份了一半的快照
DELETE _snapshot/my_backup/snapshot_name
</code></pre>
<p>这里我取一个仓库名为 my_backup，快照名为 alert_snap，要备份的 index 为 .nina_view 和 cc-zabbix-2018.01.05。</p>
<h3 id="toc-heading-8">6. 将数据迁移到另一个环境</h3>
<div>bash<i></i><i></i></div>
<pre><code># 备份创建好之后，在仓库目录/media/es/es_backup里是这样的：
-rw-r--r-- 1 elasticsearch elasticsearch  317 Jan 22 17:44 index-0
-rw-r--r-- 1 elasticsearch elasticsearch    8 Jan 22 17:44 index.latest
drwxr-xr-x 4 elasticsearch elasticsearch 4096 Jan 22 17:44 indices/
-rw-r--r-- 1 elasticsearch elasticsearch  103 Jan 22 17:44 meta-9KWgeCYtSBqqVrfD42bsNw.dat
-rw-r--r-- 1 elasticsearch elasticsearch  237 Jan 22 17:44 snap-9KWgeCYtSBqqVrfD42bsNw.dat
</code></pre>
<h3 id="toc-heading-9">7. 在目标环境下，重复上面1~4步，建立仓库</h3>
<p>将源集群的备份内容（/media/es/es_backup 里的所有文件），复制到迁移目标的仓库目录里，接下来就是类似批量导入了。</p>
<div>bash<i></i><i></i></div>
<pre><code># 如果索引已经存在目标的集群，需要先关闭索引，恢复数据后再开启
POST /index_name/_close
POST _snapshot/my_backup/snapshot_name/_restore
POST /index_name/_open

# 从快照中恢复指定的索引，并给索引重命名
# indices里面可以写多个索引名，中间用逗号隔开
# rename_pattern可以写完整的索引名，也可以用正则匹配索引名的局部
# rename_replacement将替换rename_pattern中匹配到的局部(如果是正则,不是将整个索引名都替换)
#下面这条语句会把index_1,index_2恢复为restored_index_1和restored_index_2
POST /_snapshot/my_backup/snapshot_1/_restore
{
  "indices": "index_1,index_2",
  "rename_pattern": "index_(.+)",
  "rename_replacement": "restored_index_$1"
}

# 查看恢复的状态
GET _snapshot/my_backup/snapshot_name/_status 
</code></pre>
<h2 id="toc-heading-10">三、集群-多节点环境</h2>
<h3 id="toc-heading-11">1. 创建共享目录</h3>
<p>(todo…我没实施过，感觉挺麻烦的，不太推荐)<br />
使用 sshfs 在 ES 集群中每个节点的相同位置挂载一个共享目录。</p>
<p>假设 ES 集群有三个节点：192.168.1.10，192.168.1.11，192.168.1.12，</p>
<p>我这里共享目录用了 /data/es_backup，ES 备份仓库目录(也是共享目录的挂在点)用了 /mnt/es_backup，可以根据实际情况调整。</p>
<div>bash<i></i><i></i></div>
<pre><code># 在每个节点上安装sshfs
sudo apt-get install sshfs

# 选取其中一个节点的目录(非系统盘)作为共享目录 &lt;/br&gt;
# 假设选择的节点ip为192.168.1.10：
mkdir /data/es_backup
chown -R elasticsearch:elasticsearch /data/es_backup
chmod -R 777 /data/es_backup

# 在每个ES节点的相同位置创建存放ES仓库的目录
mkdir /mnt/es_backup
chown -R elasticsearch:elasticsearch /mnt/es_backup
chmod -R 777 /mnt/es_backup
# 每个节点挂载共享目录，执行同样的操作。$user为用户，一般为root，回车后输入密码，其中的参数-o allow_other允许了其他用户访问这个目录
sshfs $user@192.168.1.10:/data/es_backup /mnt/es_backup -o allow_other
# 如果修改了默认ssh端口, 比如23566, 则可以这样:
sshfs $user@192.168.1.10:/data/es_backup /mnt/es_backup -p 23566 -o allow_other

# 测试运行ES的用户是否有对共享目录的写权限
sudo su - elasticsearch
touch /mnt/es_backup/test.txt

# 修改每个节点的elasticsearch.yml文件，添加path.repo配置
path.repo: ["/mnt/es_backup"]
</code></pre>
<p>接下来的操作和上面单节点一样，重启 es，建立仓库，创建快照等等。</p>
<div>bash<i></i><i></i></div>
<pre><code># 在共享目录下为集群创建共享仓库
PUT _snapshot/my_backup
{
  "type": "fs",
  "settings": {
    "location": "/mnt/es_backup",
    "compress": true
  }
}
# 后面步骤省略...
</code></pre>
<p>最后补充一下：取消挂载共享目录，不要直接删除挂载目录，在每个节点下执行下面命令：</p>
<div>bash<i></i><i></i></div>
<pre><code># 这个命令会断开远程连接同时清空 /mnt/es_backup 目录。
fusermount -u /mnt/es_backup
</code></pre>
<p>类似的实现文件共享的方法还有 nfs 和 samba（支持 window 和 linux 互相访问）。</p>
<h3 id="toc-heading-12">2. 借助第三方工具</h3>
<p>第三方迁移工具，网上看了下，主要有三个：</p>
<ul>
<li>elasticsearch-dump</li>
<li>elasticsearch-exporter</li>
<li><a href="https://elasticsearch.cn/article/78" target="_0" rel="external nofollow noopener noreferrer">elasticsearch-migration</a></li>
</ul>
<p>优点：方便，快速。支持的功能很多(数据迁移、mapping迁移等等)。</p>
<p>缺点：原理是用了 scroll+bulk，百万、千万级别条数的数据可以使用，数据量过大还是老老实实用我上面整理的快照方法吧。<br />
备注：对 ES 操作时候，一些报错没有捕获到并写入 log。比如我们只允许自动创建 <code>cc-</code> 开头的索引，迁移生成的新索引需要改名为别的名字，你会发现迁移完，数据没有进去，这也算是第三方工具的不足之处，不过它应该会不断完善。</p>
<h2 id="toc-heading-13">四、总结</h2>
<p>不管是运维也好，开发也好，对数据的备份和迁移是经常要做的事。针对环境的不同特别是数据量的差异，需要适时选择合适的方式。</p>
<p>有时候也要根据自己的具体需求而定，比如为了辅助自己开发，需要回放数据，那完全可以编写一些简单的脚本来实现。</p>
<p>我写过几个简单的脚本，放在 <a title="GitHub" href="https://github.com/winyuan" target="_0" rel="external nofollow noopener noreferrer">GitHub</a> 上：</p>
<ul>
<li><a href="https://github.com/winyuan/es_replay" target="_0" rel="external nofollow noopener noreferrer">es_replay</a><br />
开发测试用途（数据导出、去重、构造和导入）</li>
<li><a href="https://github.com/winyuan/es_assistant" target="_0" rel="external nofollow noopener noreferrer">es_assistant</a><br />
一些用于协助开发和测试的 es 交互脚本</li>
<li><a href="https://github.com/winyuan/es_monitor" target="_0" rel="external nofollow noopener noreferrer">es_monitor</a><br />
Elaticsearch 部署机的信息采集脚本（这个是很久很久以前写的，那时候刚学 ES，能直接用，功能上没问题，但代码完全可以更优化一下，最近忙着学其他东西，所以一直没去动它。）</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/elasticsearchsuoyinbeifenyuqianyi.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Elasticsearch部署步骤</title>
		<link>http://www.eavea.com/blog/index.php/elasticsearchbushubuzhou.html</link>
		<comments>http://www.eavea.com/blog/index.php/elasticsearchbushubuzhou.html#comments</comments>
		<pubDate>Tue, 14 Apr 2020 07:50:21 +0000</pubDate>
		<dc:creator>eavea</dc:creator>
				<category><![CDATA[运维知识]]></category>
		<category><![CDATA[Elasticsearch]]></category>

		<guid isPermaLink="false">http://www.eavea.com/blog/?p=64</guid>
		<description><![CDATA[Elasticsearch部署步骤 现在官方已经出到了ES7 beta，不过现在为止用的最多也是比较稳定的是5 [&#8230;]]]></description>
				<content:encoded><![CDATA[<div>Elasticsearch部署步骤</div>
<blockquote><p>现在官方已经出到了ES7 beta，不过现在为止用的最多也是比较稳定的是5.x。<br />
这里我简单记录下针对5.x版本的部署配置过程，暂不考虑优化（后面再总结优化相关的笔记）。</p></blockquote>
<h2 id="toc-heading-1">一、环境</h2>
<ul>
<li>Ubuntu 14.04/16、04</li>
<li>JDK1.8</li>
<li>Elasticsearch 5.6</li>
</ul>
<h2 id="toc-heading-2">二、安装JDK</h2>
<h3 id="toc-heading-3">1. 下载安装</h3>
<p><a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html" target="_0" rel="external nofollow noopener noreferrer">http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html</a></p>
<div><img alt="jdk_download.png" src="https://www.wenyuanblog.com/medias/blogimages/jdk_download.png" data-original="/medias/blogimages/jdk_download.png" /></div>
<p>将刚刚下载的文件拷贝到 /opt 目录下，<br />
解压 jdk 到当前目录，使用命令 <code>tar -zxvf jdk-8u161-linux-x64.tar.gz</code></p>
<p>&nbsp;</p>
<p>修改文件名 <code>mv jdk1.8.0_161 jdk1.8</code><br />
至此，jdk1.8 已经全部安装完成了。</p>
<h3 id="toc-heading-4">2. 配置环境变量</h3>
<p>修改 <code>vim /etc/profile</code> ，最底部添加:</p>
<pre><code># Sun JDK profile
export JAVA_HOME=/opt/jdk1.8
export JRE_HOME=${JAVA_HOME}/jre  
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib  
export PATH=${JAVA_HOME}/bin:$PATH
</code></pre>
<p>运行 <code>source /etc/profile</code>，使 /etc/profile 文件生效。</p>
<p>使用 <code>java -version</code> 和 <code>javac -version</code> 命令查看 jdk 版本及其相关信息，不会出现 command not found 错误，且显示的版本信息与前面安装的一致。</p>
<p><code>echo $JAVA_HOME</code>, <code>echo $CLASSPATH</code>, <code>echo $PATH</code>，看看自己的配置是否都正确。</p>
<h3 id="toc-heading-5">3. 开机设置</h3>
<p>每次重启服务器的时候，会发现 jdk 版本不正确，或者使用 <code>java -version</code> 显示不是所需版本，使用　<code>javac -version</code> 会出现 command not found 错误。</p>
<p>解决方法是再次运行 <code>source /etc/profile</code>，使 /etc/profile 文件生效。显然每次这么操作很麻烦。</p>
<p>因此我们编辑 <code>vim ~/.bashrc</code>，最后加一句</p>
<pre><code>source /etc/profile
</code></pre>
<h2 id="toc-heading-6">三、安装Elasticsearch</h2>
<h3 id="toc-heading-7">1. 下载安装</h3>
<p>登录官网 <a href="https://www.elastic.co/cn/downloads。" target="_0" rel="external nofollow noopener noreferrer">https://www.elastic.co/cn/downloads。</a></p>
<p>选择下载 elasticsearch，根据需要选择对应的安装包，这里选择 5.6 版本，下载完后得到 elasticsearch-5.6.0.tar.gz</p>
<p>操作系统中创建一个新用户专门用来管理 es：<code>adduser elasticsearch</code></p>
<p>用 elasticsearch 用户将 elasticsearch-5.6.0.tar.gz 拷贝到 /opt 目录下。</p>
<p>解压到当前目录，使用命令 <code>tar -zxvf elasticsearch-5.6.0.tar.gz</code>。</p>
<p>删除压缩文件，使用命令 <code>rm -f elasticsearch-5.6.0.tar.gz</code>。</p>
<p>至此，elasticsearch 安装完成</p>
<h3 id="toc-heading-8">2. ES集群需要改的系统配置</h3>
<p><code>vim /etc/security/limits.conf</code></p>
<pre><code>* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
* soft memlock unlimited
* hard memlock unlimited
* - nofile 65536

root soft nofile 65536
root hard nofile 131072
root soft nproc 2048
root hard nproc 4096
root soft memlock unlimited
root hard memlock unlimited
root - nofile 65536
</code></pre>
<p><code>vim /etc/sysctl.conf</code></p>
<pre><code>vm.max_map_count=655360
vm.swappiness = 0
</code></pre>
<p>并执行 <code>sysctl -p</code></p>
<p>如果是 supervisor 托管的，修改 /etc/supervisord.conf 中的：<br />
minfd = 65536<br />
并重启 supervisor。</p>
<h3 id="toc-heading-9">3. 修改ES配置文件elasticsearch.yml</h3>
<pre><code>bootstrap.memory_lock: false
bootstrap.system_call_filter: false

cluster.name: elasticsearch
node.name: 192.168.10.201
node.master: true
node.data: true
http.enabled: true
network.host: 0.0.0.0
discovery.zen.ping.unicast.hosts: ["192.168.10.198","192.168.10.201"]

http.port: 9200

script.engine.groovy.inline.update: on
script.engine.groovy.inline.search: on
script.engine.groovy.inline.aggs: on
script.max_compilations_per_minute: 10000

path.data: /data/es

action.auto_create_index: cc-*,sc-*,.nina*,.security,.monitoring*,.watches,.triggered_watches,.watcher-history*

</code></pre>
<p>同时也要指定一下 jvm.options（同级目录下的一个配置文件） 里的 jvm 虚拟机内存。</p>
<h3 id="toc-heading-10">4. ES交给supervisor托管</h3>
<pre><code>[program:elasticsearch]
user = elasticsearch
startsecs = 3
autostart = true
autorestart = true
startretries = 3
stdout_logfile=NONE
stderr_logfile=NONE
environment = JAVA_HOME="/opt/jdk/", ES_JAVA_OPTS = "-Xms8g -Xmx8g"
command = /opt/elasticsearch/bin/elasticsearch
</code></pre>
<h2 id="toc-heading-11">四、安装Kibana</h2>
<h3 id="toc-heading-12">1. 从官网下载和es一样版本的Kibana</h3>
<p>拷贝到 /opt 目录，解压，修改配置文件 kibana.yml。</p>
<pre><code>server.host: "192.168.10.201"
elasticsearch.url: "http://192.168.10.198:9200"
</code></pre>
<h3 id="toc-heading-13">2. Kibana交给supervisor托管</h3>
<pre><code>[program:kibana]
startsecs = 3
autostart = true
autorestart = true
startretries = 3
redirect_stderr = true
command = /opt/kibana/bin/kibana
stdout_logfile = /var/log/kibana.log
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.eavea.com/blog/index.php/elasticsearchbushubuzhou.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
