美文网首页
Elasticsearch 入门到精通

Elasticsearch 入门到精通

作者: 木木一直在哭泣 | 来源:发表于2024-01-13 11:45 被阅读0次

    1. 简介

    Elasticsearch 是一个功能强大的分布式搜索和分析引擎,具备快速的数据处理能力、高可用性、灵活的扩展性和丰富的查询功能,广泛应用于日志分析、实时搜索、数据分析和监控等领域。通过其分布式架构和弹性扩展性,它可以应对大数据量和高查询速度的需求。

    2. 安装和设置

    2.1 Elasticsearch安装

    2.2 Kinaba安装

    3. 基本概念

    3.1index索引

    一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。可类比mysql中表

    3.2Filed字段

    相当于是数据表的字段,对文档数据根据不同属性进行的分类标识 。

    3.3映射mapping

    mapping是处理数据的方式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其它就是处理es里面数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。相当于mysql中的创建表的过程,设置主键外键等等

    3.4 document文档

    一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。 插入索引库以文档为单位,类比与数据库中的一行数据

    3.5 集群cluster

    一个集群就是由一个或多个节点组织在一起,它们共同持有整个的数据,并一起提供索引和搜索功能。一个集群由 一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集 群的名字,来加入这个集群。

    3.6 节点node

    一个节点是集群中的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一 个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的 时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对 应于Elasticsearch集群中的哪些节点。
    一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫 做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此, 它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
    在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点, 这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。

    3.7分片和复制 shards&replicas

    一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因: 1)允许你水平分割/扩展你的内容容量。 2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。
    至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
    在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
    复制之所以重要,有两个主要原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。
    默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。

    4. 索引和查询数据

    • 展示如何创建索引和映射。
    创建索引
    #创建了名字为orders的index,类似于mysql的table
    PUT /orders
    {
      "mappings": {
        "properties": {
          "order_id": {
            "type": "keyword"
          },
          "customer_name": {
            "type": "text"
          },
          "order_date": {
            "type": "date"
          },
          "total_amount": {
            "type": "float"
          },
          "products": {
            "type": "nested",
            "properties": {
              "product_id": {
                "type": "keyword"
              },
              "product_name": {
                "type": "text"
              },
              "price": {
                "type": "float"
              }
            }
          }
        }
      }
    }
    
    创建文档
    #创建了doc,类似于mysql的行数据
    POST /orders/_doc
    {
      "order_id": "123456789",
      "customer_name": "John Doe",
      "order_date": "2022-12-31T23:59:59",
      "total_amount": 199.99,
      "products": [
        {
          "product_id": "1",
          "product_name": "Product A",
          "price": 99.99
        },
        {
          "product_id": "2",
          "product_name": "Product B",
          "price": 100
        }
      ]
    }
    
    查询文档
    GET /orders/_search
    {
      "query": {
        "match_all": {}
      }
    }
    

    5. 高级搜索功能

    5.1全文搜索、精确搜索、模糊搜索和通配符搜索

    1. 全文搜索:假设你希望在 "customer_name" 字段中执行全文搜索,找到包含关键词 "John Doe" 的订单。你可以使用 match 查询来完成:
    {
      "query": {
        "match": {
          "customer_name": "John Doe"
        }
      }
    }
    

    这将返回所有 "customer_name" 字段中包含 "John" 或 "Doe" 单词的订单。

    1. 精确搜索:如果你希望根据订单的唯一标识符进行精确匹配搜索,可以使用 term 查询。以下是一个示例:
    {
      "query": {
        "term": {
          "id": "123456789"
        }
      }
    }
    

    这将仅返回与订单标识符为 "123456789" 完全匹配的订单。

    1. 模糊搜索:假设你想要模糊搜索顾客姓名字段,以找到拼写类似于 "John Doe" 的订单。你可以使用 fuzzy 查询来实现:
    {
      "query": {
        "fuzzy": {
          "customer_name": {
            "value": "John Doe",
            "fuzziness": "auto"
          }
        }
      }
    }
    

    这将返回与 "John Doe" 相近的顾客姓名,考虑到拼写的相似性。

    1. 通配符搜索:如果你想要搜索以 "J" 开头的顾客姓名的订单,可以使用通配符搜索。以下是一个示例:
    {
      "query": {
        "wildcard": {
          "customer_name": "J*"
        }
      }
    }
    

    5.2 如何使用布尔查询、过滤器、聚合和排序来构建复杂的查询。

    好的,让我们用 orders 这个示例来解释布尔查询、过滤器、聚合和排序的使用。

    先增加properties和doc:

    PUT /orders
    {
      "mappings": {
        "properties": {
          "id": {"type": "keyword"},
          "customer_name": {"type": "text"},
          "status": {"type": "keyword"},
          "price": {"type": "float"},
          "order_date": {"type": "date"}
        }
      }
    }
     
    POST /orders/_bulk
    { "index": { "_id": "1" } }
    { "id": "123456789", "customer_name": "John Doe", "status": "pending", "price": 100.00, "order_date": "2022-02-15" }
    { "index": { "_id": "2" } }
    { "id": "987654321", "customer_name": "Jane Smith", "status": "shipped", "price": 50.00, "order_date": "2022-03-01" }
    { "index": { "_id": "3" } }
    { "id": "456789123", "customer_name": "Bob Johnson", "status": "cancelled", "price": 33.00, "order_date": "2022-02-01" }
    

    首先,我们来创建一个 index 和一个包含一些订单的示例数据:

    PUT /orders
    {
      "mappings": {
        "properties": {
          "id": {"type": "keyword"},
          "customer_name": {"type": "text"},
          "status": {"type": "keyword"},
          "price": {"type": "float"},
          "order_date": {"type": "date"}
        }
      }
    }
     
    POST /orders/_bulk
    { "index": { "_id": "1" } }
    { "id": "123456789", "customer_name": "John Doe", "status": "pending", "price": 100.00, "order_date": "2022-02-15" }
    { "index": { "_id": "2" } }
    { "id": "987654321", "customer_name": "Jane Smith", "status": "shipped", "price": 50.00, "order_date": "2022-03-01" }
    { "index": { "_id": "3" } }
    { "id": "456789123", "customer_name": "Bob Johnson", "status": "cancelled", "price": 33.00, "order_date": "2022-02-01" }
    

    现在,我们将使用以下示例查询、过滤器、聚合和排序对数据进行操作:

    1. 布尔查询:假设你想要查找价格在 20 到100 之间的处于 "pending" 状态的订单,也就是要执行一个 "must" 和 "must" 的布尔查询,用于组合多个条件以获取更精确的结果。以下是一个示例查询:
    {
      "query": {
        "bool": {
          "must": [
            {
              "range": {
                "price": {
                  "gte": 20,
                  "lte": 100
                }
              }
            },
            {
              "match": {
                "status": "pending"
              }
            }
          ]
        }
      }
    }
    

    这将在满足价格在 20 到100,以及状态为 "pending" 的订单中搜索。

    1. 过滤器:假设你想要查找订单日期在 2022 年 2 月份的订单,也就是按照日期进行查询。这个时候我们可以用过滤器来实现:
    {
      "query": {
        "bool": {
          "filter": {
            "range": {
              "order_date": {
                "gte": "2022-02-01",
                "lte": "2022-02-28"
              }
            }
          }
        }
      }
    }
    

    这将筛选出日期在 2022 年 2 月份的订单。

    1. 聚合:假设你想要按照顾客名字将订单分组,计算每个顾客的平均订单总价和最大订单总价。以下是一个示例聚合:
    {
      "size": 0,
      "aggs": {
        "customer_orders": {
          "terms": {
            "field": "customer_name"
          },
          "aggs": {
            "avg_order_total": {
              "avg": {
                "field": "price"
              }
            },
            "max_order_total": {
              "max": {
                "field": "price"
              }
            }
          }
        }
      }
    }
    

    这将按顾客名称聚合订单,并计算每个顾客的平均和最大订单总价。

    1. 排序:假设你想要以价格降序对订单进行排序。你可以在查询中添加一个 "sort" 参数来实现:
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        { "price": { "order": "desc" } }
      ]
    }
    

    这将按价格降序排序所有订单。

    可以看到,使用 Elasticsearch 的查询、过滤器、聚合和排序等功能可以构建复杂的查询,提高数据检索效率和准确性。这里仅提供了一些简单的示例,实际应用需要根据不同的场景和需求进行不

    6. 搜索优化

    6.1 - 介绍如何使用索引优化器和分析器来提升搜索的性能。

    6.2 内存配置

    当为 Elasticsearch 分配内存时,需要考虑多个因素,如数据量、索引结构、查询需求等。下面是根据不同场景建议的分配策略:

    1. 全文搜索场景:
    • 对于小规模或中等规模的索引(例如数百万条文档),建议将 Elasticsearch 堆内存分配为整个可用内存的 50% ~ 75%。这将允许 Elasticsearch 建立足够的缓存,以提供高效的索引和查询性能。在这种情况下,需要考虑避免存储过多的数据,以免触发 JVM 的 GC。

    • 对于大规模的索引(例如数千万条文档),由于内存资源有限,建议对 Elasticsearch 堆内存进行更小的配置(例如设置为整个可用内存的 25% ~ 50%)。此时,需要使用更多的硬盘 I/O 和操作系统缓存来补充内存不足的情况。对于此类场景,建议使用 SSD 以提高磁盘操作的性能。

    1. 聚合和排序场景:
    • 对于仅基于数字和日期字段的聚合和排序操作,可以将 Elasticsearch 堆内存设置为较小的值(例如 2GB ~ 4GB)。此时,需要留出一定的内存(例如 4GB ~ 8GB)用于操作系统缓存和 Lucene 的缓存。这将允许 Elasticsearch 建立足够的缓存,而无需使用过多的堆内存。

    • 对于同时处理数字、日期和文本字段的聚合和排序操作,建议将 Elasticsearch 堆内存扩大(例如 16GB ~ 32GB)。此时,需要留出一定的内存(例如 8GB ~ 16GB)用于操作系统缓存和 Lucene 的缓存。在这种情况下,需要注意堆内存的使用情况,并确保 Elasticsearch 不会触发 JVM 的 GC。

    1. 多租户场景:
    • 对于多租户场景,建议将 Elasticsearch 堆内存划分为多个分区,每个分区仅被单个租户使用。对于每个租户,可以根据其负载和实际需求进行不同的配置。例如,高负载的租户可以被分配更多的堆内存,而低负载的租户则可以被分配较少的堆内存。这种策略将允许 Elasticsearch 更好地隔离每个租户的资源,以保证系统的平稳运行。

    7. 故障排除和监控

    • 提供一些故障排除的技巧和常见问题的解决方案。

    • 介绍如何使用监控工具来实时监测 Elasticsearch 集群的状态和性能。

    8. 扩展 Elasticsearch

    • 解释如何使用集群、节点和索引级别的设置来扩展 Elasticsearch。

    • 介绍如何使用插件和自定义脚本来扩展 Elasticsearch 的功能。

    9. 参考资料和进一步学习

    相关文章

      网友评论

          本文标题:Elasticsearch 入门到精通

          本文链接:https://www.haomeiwen.com/subject/nxbfodtx.html