zoukankan      html  css  js  c++  java
  • Elasticsearch核心技术(五):搜索API和搜索运行机制

    本文将从数据存储和搜索的角度简单分析Elasticsearch的搜索运行机制,主要涉及搜索API、搜索机制、存在问题和解决方案。

    4.1 Search API

    Search API允许用户执行一个搜索查询并返回匹配查询的搜索命中结果。

    Elasticsearch查询主要有两种方式:URI SearchRequest Body Search

    • URI Search:通过URI参数实现搜索,特点是操作简便,仅包含部分查询语法,常用参数如下:
      q:指定查询语句,使用Query String Syntax
      df:默认字段,不指定时,会对所有字段进行查询
      sort:排序
      profile:用于查看查询是如何被执行的

    • Request Body Search:完备的查询语法Query DSL,所以还是建议使用Request Body Search。

    4.2 深入了解Search运行机制

    建议先参考上篇Elasticsearch核心技术(四):分布式存储架构与索引原理分析,其中主要介绍了ES的分布式存储架构和原理。

    4.2.1 Query-then-Fetch运行机制

    Elasticsearch的分布式搜索的运行机制称为Query-then-Fetch。具体分为Query和Fetch两个阶段:

    Query阶段

    用户发出搜索请求到达ES节点。节点收到请求后,会以协调节点(Coordinating Node)的身份,在6个主副分片中随机选择3个分片,发送查询请求。

    被选中的节点,进行排序(根据score值进行排序)。然后每个分片都返回 From+size 个排序后的文档id和排序值给协调节点。 注意这里返回的是文档id。

    Fetch阶段

    Coordinating节点将Query阶段从每个分片获取的排序的文档id列表重新进行排序,选取 From 到 From+size 个文档的id。

    multi get请求的方式,到相应的分片获取详细的文档数据。

    4.2.2 为什么需要两阶段才能完成搜索

    因为Elasticsearch在查询的时候不知道文档位于哪个分片,因此索引的所有分片都要参与搜索,然后协调节点将结果合并,在根据文档ID获取文档内容。例如现在有5个分片,需要查询匹配度Top10的数据,那么每个分片都要查询出当前分片的Top10的数据,协调节点将5×10个结果再次进行排序,返回Top10的结果给客户端。

    4.2.3 Query-then-Fetch存在问题和解决方案

    Query-then-Fetch存在问题分为两方面,一个是性能问题,一个是相关性算分问题。

    • 性能问题

    性能问题主要表现为深度分页的问题。Elasticsearch数据是分片存储的,数据分布在多台机器上。有这样一个场景,如何获取前1000个文档?当获取从990-1000的文档时候,会在每个分片上面都先获取1000个文档,然后再由协调节点聚合所有分片的结果在排序选取前1000个文档。

    这个过程有什么问题吗?当然是有的,页数越深,处理文档越多,占用内存越多,耗时越长。所以要尽量避免深度分页。当然,ES官方也注意了这个问题,所以通过index.max_result_window限定最多到10000条数据。当然我们也可以根据业务需要修改这个参数,这也解释了:为什么Google搜索结果只有相关度最高的17页结果,百度只有76页的结果,原因之一是受限于Elasticsearch深度分页的性能问题。

    • 相关性算分问题
      另外一个问题是相关性算分不准确问题。每个分片都基于自己分片上面的数据进行相关度计算。这会导致打分偏离的情况,特别是数据量很少的时候。相关性算分在分片之间是相互独立。当文档总数很少的情况下,如果主分片大于1,如果主分片数越多,相关性算分会越不准。

    • 如何解决算分不准的问题?

    1. 当数据量不大的时候,将主分片数设置为1;当数据量足够大的时候,只要保证文档均匀分布在各个分片上面,结果一般不会出现偏差
    2. 使用DFS Query Then Fetch
      在搜索的URL中指定参数 _search?search_type=dfs_query_then_fetch ;这样就可以保证每个分片把各个分片的词频和文档频率进行搜集,然后进行一次相关性算分。但是这样会耗费更多的CPU和内存资源,执行性能较低。
    • 如何避免深度分页的问题?

    使用Search_After
    ES提供实时的下一页文档获取功能,这个功能只能下一页,不能上一页;
    不能指定页数,不能使用from参数;

    • 三种分页方式对比:
    类型 场景
    From/Size 需要实时获取顶部的部分文档,且需要自由翻页
    Scroll 需要全部文档,如导出所有数据的功能
    Search_After 需要全部文档,不需要自由翻页

    4.3 总结

    经济基础决定上层建筑,ES的分片存储决定了搜索机制。其实存储和搜索不能分割开来看,只存储不可搜索,这个存储是没有意义的;只搜索没有存储(数据源)是空中楼阁。

    由于博主也是在攀登的路上,文中可能存在不当之处,欢迎各位多指教! 如果文章对您有用,那么请点个”推荐“,以资鼓励!
  • 相关阅读:
    android 之 ListView相关
    android 之 菜单
    android 之 Dialog
    android 之 View
    android 之 service
    android 之 Intent、broadcast
    Service Broadcast简单音乐播放功能
    剑指offer面试题43:n个筛子的点数
    C# LINQ语法
    C# Linq
  • 原文地址:https://www.cnblogs.com/sgh1023/p/15743264.html
Copyright © 2011-2022 走看看