实时搜索引擎Elasticsearch

一、什么是Elasticsearch

  • 在解释什么是Elasticsearch之前,让我们来回顾一下我们每天都在网页上面重复做的一件事情–“搜索”。没错,当我们需要了解一个东西的时候,我们会不自觉的打开搜索网站,例如百度,360,搜狗等;或者当我们需要购买一件物品时,我们打开淘宝,京东,唯品会等购物网站,做的第一件事情,仍然还是搜索我们需要的物品的关键词。
  • Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

二、安装ElasticSearch

  1. ElasticSearch下载地址:
    https://www.elastic.co/downloads/elasticsearch

  2. 下载安装包后解压
    在这里插入图片描述

  3. 解压后bash运行bin/elasticsearch

在这里插入图片描述
注意:可以一起安装ELK
elasticsearch (es) :通过搭建群集;存储日志数据,索引日志数据
logstash :收集日志,收集到了后给es存储
kibana :视图形式展现日志信息,更加人性化
版本控制:ELK在下载时,下载版本号一致的版本即可。

三、搭建集群

(一)集群健康

Elasticsearch 的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是 集群健康 , 它在 status 字段中展示为 green 、 yellow 或者 red 。

GET /_cluster/health

status 字段是我们最关心的。
status 字段指示着当前集群在总体上是否工作正常。它的三种颜色含义如下:

  1. green
    所有的主分片和副本分片都正常运行。
  2. yellow
    所有的主分片都正常运行,但不是所有的副本分片都正常运行。
  3. red
    有主分片没能正常运行。

(二)搭建集群

当你在同一台机器上启动了第二个节点时,只要它和第一个节点有同样的 cluster.name 配置,它就会自动发现集群并加入到其中。 但是在不同机器上启动节点的时候,为了加入到同一集群,你需要配置一个可连接到的单播主机列表。 详细信息请查看最好使用单播代替组播。

注意:通过config目录下的elasticsearch.yml修改配置

四、文档元数据和数据

注意:在ES中以 '_' 开头的都是关键词。并且在{}中的一级参数也是关键词。只有_source{}里面的数据才是我们自己定义的参数

一个文档不仅仅包含它的数据 ,也包含 元数据 —— 有关 文档的信息。 三个必须的元数据元素如下:
_index
文档在哪存放(索引库)
_type
文档表示的对象类别(类型)
_id
文档唯一标识

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out...",
      "date":  "2014/01/01"
  }
}

五、创建文档——C

ES中创建和修改文档的语句是相同的,如果已经存在文档那么会覆盖掉之前的来达到更新的效果。
当我们索引一个文档,怎么确认我们正在创建一个完全新的文档,而不是覆盖现有的呢?

请记住, _index 、 _type 和 _id 的组合可以唯一标识一个文档。所以,确保创建一个新文档的最简单办法是,使用索引请求的 POST 形式让 Elasticsearch 自动生成唯一 _id :
方式一:指定id

# PUT /{索引库}/{类型}/{id}
PUT /website/blog/123
{
  "title": "My first blog entry",
  "text":  "I am starting to get the hang of this...",
  "date":  "2014/01/02"
}

方式二:自动生成id

POST /website/blog/
{ ... }

方式三:参数指定这个是创建文档语句

PUT /website/blog/123?op_type=create
{ ... }
PUT /website/blog/123?op_type=create
{ ... }

如果创建新文档的请求成功执行,Elasticsearch 会返回元数据和一个 201 Created 的 HTTP 响应码。

另一方面,如果具有相同的 _index 、 _type 和 _id 的文档已经存在,Elasticsearch 将会返回 409 Conflict 响应码,以及如下的错误信息:

{
   "error": {
      "root_cause": [
         {
            "type": "document_already_exists_exception",
            "reason": "[blog][123]: document already exists",
            "shard": "0",
            "index": "website"
         }
      ],
      "type": "document_already_exists_exception",
      "reason": "[blog][123]: document already exists",
      "shard": "0",
      "index": "website"
   },
   "status": 409
}

六、获取文档——R

(一)返回文档全部数据

GET /website/blog/123?pretty
{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out...",
      "date":  "2014/01/01"
  }
}

(二)返回部分文档数据

# title,text为属性。指定返回哪几个属性
GET /website/blog/123?_source=title,text
{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 1,
  "found" :   true,
  "_source" : {
      "title": "My first blog entry" ,
      "text":  "Just trying this out..."
  }
}

(三)返回纯数据文档

如果你只想得到 _source 字段,不需要任何元数据,你能使用 _source 端点:

GET /website/blog/123/_source
{
   "title": "My first blog entry",
   "text":  "Just trying this out...",
   "date":  "2014/01/01"
}

(四)返回多个文档

Elasticsearch 的速度已经很快了,但甚至能更快。 将多个请求合并成一个,避免单独处理每个请求花费的网络延时和开销。 如果你需要从 Elasticsearch 检索很多文档,那么使用 multi-get 或者 mget API 来将这些检索请求放在一个请求中,将比逐个文档请求更快地检索到全部文档。

mget API 要求有一个 docs 数组作为参数,每个元素包含需要检索文档的元数据, 包括 _index 、 _type 和 _id 。如果你想检索一个或者多个特定的字段,那么你可以通过 _source 参数来指定这些字段的名字
例如:

GET /_mget
{
   "docs" : [
      {
         "_index" : "website",
         "_type" :  "blog",
         "_id" :    2
      },
      {
         "_index" : "website",
         "_type" :  "pageviews",
         "_id" :    1,
         "_source": "views"
      }
   ]
}

响应:

{
   "docs" : [
      {
         "_index" :   "website",
         "_id" :      "2",
         "_type" :    "blog",
         "found" :    true,
         "_source" : {
            "text" :  "This is a piece of cake...",
            "title" : "My first external blog entry"
         },
         "_version" : 10
      },
      {
         "_index" :   "website",
         "_id" :      "1",
         "_type" :    "pageviews",
         "found" :    true,
         "_version" : 2,
         "_source" : {
            "views" : 2
         }
      }
   ]
}

七、判断文档是否存在——R

如果只想检查一个文档是否存在–根本不想关心内容—​那么用 HEAD 方法来代替 GET 方法。 HEAD 请求没有返回体,只返回一个 HTTP 请求报头:

curl -i -XHEAD http://localhost:9200/website/blog/123

八、更新文档——U

在 Elasticsearch 中文档是 不可改变 的,不能修改它们。相反,如果想要更新现有的文档,需要 重建索引 或者进行替换, 我们可以使用相同的 index API 进行实现,在 索引文档 中已经进行了讨论。

PUT /website/blog/123
{
  "title": "My first blog entry",
  "text":  "I am starting to get the hang of this...",
  "date":  "2014/01/02"
}

更新部分数据:

  1. update 请求最简单的一种形式是接收文档的一部分作为 doc 的参数, 它只是与现有的文档进行合并。对象被合并到一起,覆盖现有的字段,增加新的字段。 例如,我们增加字段 tags 和 views 到我们的博客文章,如下所示:
POST /website/blog/1/_update
{
   "doc" : {
      "tags" : [ "testing" ],
      "views": 0
   }
}
  1. 假设我们需要在 Elasticsearch 中存储一个页面访问量计数器。 每当有用户浏览网页,我们对该页面的计数器进行累加。但是,如果它是一个新网页,我们不能确定计数器已经存在。 如果我们尝试更新一个不存在的文档,那么更新操作将会失败。

在这样的情况下,我们可以使用 upsert 参数,指定如果文档不存在就应该先创建它:

POST /website/pageviews/1/_update
{
   "script" : "ctx._source.views+=1",
   "upsert": {
       "views": 1
   }
}

九、删除文档——D

删除文档的语法和我们所知道的规则相同,只是使用 DELETE 方法:

DELETE /website/blog/123

十、乐观锁

在我们获取文档时,发现每个文档都是有一个版本号的。ES通过比较版本号来判断数据是否已经被别人修改。

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
  }
}

在更新时携带一个版本号,如果文档的版本号与携带的一致,才进行更新。

PUT /website/blog/1?version=1 
{
  "title": "My first blog entry",
  "text":  "Starting to get the hang of this..."
}

十一、批量操作

与 mget 可以使我们一次取回多个文档同样的方式, bulk API 允许在单个步骤中进行多次 create 、 index 、 update 或 delete 请求。 如果你需要索引一个数据流比如日志事件,它可以排队和索引数百或数千批次。
格式:

{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...

这种格式类似一个有效的单行 JSON 文档 流 ,它通过换行符(\n)连接到一起。注意两个要点:

每行一定要以换行符(\n)结尾, 包括最后一行 。这些换行符被用作一个标记,可以有效分隔行。
这些行不能包含未转义的换行符,因为他们将会对解析造成干扰。这意味着这个 JSON 不 能使用 pretty 参数打印。
action/metadata 行指定 哪一个文档 做 什么操作 。

action 必须是以下选项之一:

create
如果文档不存在,那么就创建它。详情请见 创建新文档。
index
创建一个新文档或者替换一个现有的文档。详情请见 索引文档 和 更新整个文档。
update
部分更新一个文档。详情请见 文档的部分更新。
delete
删除一个文档。详情请见 删除文档。
metadata 应该指定被索引、创建、更新或者删除的文档的 _index 、 _type 和 _id 。

例子:

POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} \n
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}\n
{ "title":    "My first blog post" }\n
{ "index":  { "_index": "website", "_type": "blog" }}\n
{ "title":    "My second blog post" }\n
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }\n
{ "doc" : {"title" : "My updated blog post"} } \n

响应:

{
   "took": 4,
   "errors": false, 
   "items": [
      {  "delete": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 2,
            "status":   200,
            "found":    true
      }},
      {  "create": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 3,
            "status":   201
      }},
      {  "create": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "EiwfApScQiiy7TIKFxRCTw",
            "_version": 1,
            "status":   201
      }},
      {  "update": {
            "_index":   "website",
            "_type":    "blog",
            "_id":      "123",
            "_version": 4,
            "status":   200
      }}
   ]
}

值得注意的是,如果批处理量太大的话。效率反而会降低
幸运的是,很容易找到这个 最佳点 :通过批量索引典型文档,并不断增加批量大小进行尝试。 当性能开始下降,那么你的批量大小就太大了。一个好的办法是开始时将 1,000 到 5,000 个文档作为一个批次, 如果你的文档非常大,那么就减少批量的文档个数。

密切关注你的批量请求的物理大小往往非常有用,一千个 1KB 的文档是完全不同于一千个 1MB 文档所占的物理大小。 一个好的批量大小在开始处理后所占用的物理大小约为 5-15 MB。

十二、分页

和 SQL 使用 LIMIT 关键字返回单个 page 结果的方法相同,Elasticsearch 接受 from 和 size 参数:

  1. size
    显示应该返回的结果数量,默认是 10
  2. from
    显示应该跳过的初始结果数量,默认是 0
GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10

注意:不要深度分页

理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点 ,协调节点对 50 个结果排序得到全部结果的前 10 个。

现在假设我们请求第 1000 页—​结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。

可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。

参考

官方文档1

官方文档2

中文ES社区

Java 使用ES1
Java使用ES2

output参考:https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
https://www.liujiajia.me/2018/11/28/logstash-save-different-logs-to-each-index/
注意logstash是默认使用内存队列,如果异常关闭可能会丢失数据,可以将数据持久化到磁盘(使用持久队列)
https://www.elastic.co/guide/en/logstash/current/persistent-queues.html#configuring-persistent-queues

解析Logstash 日志字段
https://www.cnblogs.com/dogfei/p/15092375.html
https://blog.csdn.net/zjcjava/article/details/99258682 重点

input file插件参考:https://www.cnblogs.com/JetpropelledSnake/p/9889275.html#_label2

解析日志:https://blog.csdn.net/zjcjava/article/details/99258682

根据log4j2输出格式生成grok-》match:http://grokconstructor.appspot.com/do/translator

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值