背景
最近在学习Elasticsearch相关的一些原理,然后在映像中ES的text字段如果存在keyword的fields,则会在聚合的时候选择keyword类型进行聚合,同时在文本检索的时候根据text类型分词检索。因此,想探究下这个的实现过程。
ES查询原理
需要了解keyword的选择郭成,需要指定如下两点:
- 字段在启动过程中如何初始化
- 查询的时候如何筛选需要的字段以及选择类型
ES初始化流程
通过以下时序图记录下ES初始化过程中的大致过程:
sequenceDiagram; Elasticsearch->>Command: 主程序入口,解析命令参数 Command->>Command: 注册closeHook,执行主函数前置hook函数beforeMain.run() Command->>EnvironmentAwareCommand: 执行环境参数初始化 EnvironmentAwareCommand->>Elasticsearch: 执行启动具体命令 Elasticsearch->>Elasticsearch: 参数解析 Elasticsearch->>Bootstrap: 执行初始化静态方法init Bootstrap->>Bootstrap: 实例化Bootstrap,初始化keepAlive线程 Bootstrap->>Bootstrap: 创建上下文环境,设置环境的日志配置 Bootstrap->>Bootstrap: 创建PID文件 Bootstrap->>Bootstrap: 检查luence版本 Bootstrap->>Bootstrap: 初始化插件进程,初始化节点 Bootstrap->>Bootstrap: 节点启动以及保活线程启动 BootStrap->>Node: 尝试启动节点 Node->>Node: 节点状态更改 Node->>Node: 各服务初始化启动 Node->>Node: Netty服务启动 alt: 当前节点为Master/Data Node->>Node: 获取GatewayMetaState实例 Node->>GatewayMetaState: 执行loadMetaState载入元信息 GatewayMetaState->>MetaStateService: 执行loadFullState方法载入全局状态以及索引状态 MetaStateService->>MetaStateService: 载入全局状态 MetaStateService->>MetaStateService: 查找所有的索引路径 MetaStateService->>MetaStateService: 解析每个索引路径,载入最新的状态 MetaStateService->>MetaStateService: 将索引状态放入全局状态内缓存 else: Node->>Node: 创建空的元信息 end Node->>Node: 启动Discovery服务以及Cluster服务 Node->>Node: 节点Transport服务开始接收请求 Node->>Node: 初始化集群状态,并监听集群状态变更 alt: 启用HTTP模块 Node->>Node: 初始化HTTP服务,并启动 end alt: 是否将端口信息写入文件 alt: 启用HTTP模块 Node->>Node: 将http端口写入 end Node->>Node: 将transport端口写入 end Node->>Node: 集群插件执行onNodeStarted方法进行节点初始化
上述流程大致将ES整个启动流程大概讲述了一遍,具体了解下在加载过程中如何解析数据文件并将其加入缓存。
在上述流程中可以找到如下这一块是重点:
sequenceDiagram; Node->>Node: 获取GatewayMetaState实例 Node->>GatewayMetaState: 执行loadMetaState载入元信息 GatewayMetaState->>MetaStateService: 执行loadFullState方法载入全局状态以及索引状态 MetaStateService->>MetaStateService: 载入全局状态 MetaStateService->>MetaStateService: 查找所有的索引路径 MetaStateService->>MetaStateService: 解析每个索引路径,载入最新的状态 MetaStateService->>MetaStateService: 将索引状态放入全局状态内缓存
载入每个索引最新的状态代码如下:
1 | public T loadLatestState(Logger logger, NamedXContentRegistry namedXContentRegistry, Path... dataLocations) throws IOException { |
在方法read
内会解析真正的文件内容。
ES聚合查询流程
ES每一次查询通过netty
服务传递查询命令,以下是聚合查询流程:
sequenceDiagram; Netty4HttpRequestHandler->>Netty4HttpRequestHandler: 读取数据 Netty4HttpRequestHandler->>Netty4HttpServerTransport: 传输请求 Netty4HttpServerTransport->>RestController: 分发请求 RestController->>RestController: 遍历所有处理器,查找匹配的handler alt 查找到匹配的: RestController->>BaseRestHandler: 处理请求 BaseRestHandler->>RestSearchAction: 解析请求获取具体的处置动作 RestSearchAction->>SearchSourceBuilder: 根据传递过来的json字符串解析请求内容 SearchSourceBuilder->>SearchSourceBuilder: 根据string token,判断不同类型,解析不同的数据 SearchSourceBuilder->>AggregatorFactories: 从字符串中构建出聚合工厂用于后续构建聚合 AggregatorFactories->>AggregatorFactories: 构建聚合工厂 AggregatorFactories->>SearchSourceBuilder: 继续解析其他内容 SearchSourceBuilder->>RestSearchAction: 解析完成 RestSearchAction->>RestSearchAction: 解析查询类型、路由、索引选项以及深度分页请求信息等等 RestSearchAction->>BaseRestHandler: 返回预处理完成的Action alt: 存在有参数未处理 BaseRestHandler->>BaseRestHandler: 抛出异常 end BaseRestHandler->>BaseRestHandler: 使用计数+1 BaseRestHandler->>RestSearchAction: 将请求交由RestSearchAction处理 RestSearchAction->>TransportSearchAction: 查询action交由具体Transport执行 TransportSearchAction->>TransportSearchAction: 根据state以及请求获取具体的索引 TransportSearchAction->>TransportSearchAction: 预处理别名 TransportSearchAction->>TransportSearchAction: 查询请求路由 TransportSearchAction->>TransportSearchAction: 获取索引在所有shards上的遍历器 TransportSearchAction->>AbstractSearchAsyncAction: 异步查询解析 AbstractSearchAsyncAction->>InitialSearchPhase: 执行异步查询请求 InitialSearchPhase->>InitialSearchPhase: 分片遍历并在每个分片上执行查询 InitialSearchPhase->>SearchQueryThenFetchAsyncAction: 传递分片信息以及查询请求 SearchQueryThenFetchAsyncAction->>TransportService: 将查询异步请求交由Transport服务来执行 TransportService->>TransportService: 交由localNodeConnection执行查询请求 TransportService->>SearchTransportService: 将请求传递 SearchTransportService->>SearchService: 执行searchService请求查询传入请求以及回调监听 SearchService->>SearchService: 执行查询解析并查询具体结果 SearchService->>QueryPhase: 查询解析 QueryPhase->>AggregationPhase: 聚合预处理,构建顶层聚合 AggregationPhase->>QueryPhase: 预处理完成 QueryPhase->>QueryPhase: 聚合语句执行 QueryPhase->>QueryPhase: 返回执行结果 QueryPhase->>SearchService: 结果返回 end
上述的整个流程过程中,有三处地方对于聚合做了处理:
- 请求字符串解析出聚合构建器
- 预处理聚合构建器,构建出top聚合
- 聚合语句执行
这三处地方,并没有对于聚合字段做特殊判断,比如在聚合的时候会直接选择keyword属性。而是需要在请求的时候,显示指定字段类型为keyword类型的标识。
总结
如果需要在聚合的时候直接使用keyword,则显示指定它。