首页 > 编程语言 >使用 JavaScript 脚本来进行复杂的查询改写

使用 JavaScript 脚本来进行复杂的查询改写

时间:2023-07-18 09:22:30浏览次数:53  
标签:网关 ctx JavaScript request 查询 改写 go path gateway

有这么一个需求:

网关里怎样对跨集群搜索进行支持的呢?我想实现: 输入的搜索请求是 lp:9200/index1/_search
这个索引在 3 个集群上,需要跨集群检索,也就是网关能否改成 lp:9200/cluster01:index1,cluster02,index1,cluster03:index1/_search 呢?
索引有一百多个,名称不一定是 app, 还可能多个索引一起的。

极限网关自带的过滤器 content_regex_replace 虽然可以实现字符正则替换,但是这个需求是带参数的变量替换,稍微复杂一点,没有办法直接用这个正则替换实现,有什么其他办法实现么?

使用脚本过滤器

当然有的,上面的这个需求,理论上我们只需要将其中的索引 index1 匹配之后,替换为 cluster01:index1,cluster02,index1,cluster03:index1 就行了。

答案就是使用自定义脚本来做,再复杂的业务逻辑都不是问题,都能通过自定义脚本来实现,一行脚本不行,那就两行。

使用极限网关提供的 JavaScript 过滤器可以很灵活的实现这个功能,具体继续看。

定义脚本

首先创建一个脚本文件,放在网关数据目录的 scripts 子目录下面,如下:

➜  gateway ✗ tree data
data
└── gateway
    └── nodes
        └── c9bpg0ai4h931o4ngs3g
            ├── kvdb
            ├── queue
            ├── scripts
            │   └── index_path_rewrite.js
            └── stats

这个脚本的内容如下:

function process(context) {
    var originalPath = context.Get("_ctx.request.path");
    var matches = originalPath.match(/\/?(.*?)\/_search/)
    var indexNames = [];
    if(matches && matches.length > 1) {
        indexNames = matches[1].split(",")
    }
    var resultNames = []
    var clusterNames = ["cluster01", "cluster02"]
    if(indexNames.length > 0) {
        for(var i=0; i<indexNames.length; i++){
            if(indexNames[i].length > 0) {
                for(var j=0; j<clusterNames.length; j++){
                    resultNames.push(clusterNames[j]+":"+indexNames[i])
                }
            }
        }
    }

    if (resultNames.length>0){
        var newPath="/"+resultNames.join(",")+"/_search";
        context.Put("_ctx.request.path",newPath);
    }
}

和普通的 JavaScript 一样,定义一个特定的函数 process 来处理请求里面的上下文信息,_ctx.request.path 是网关内置上下文的一个变量,用来获取请求的路径,通过 context.Get("_ctx.request.path") 在脚本里面进行访问。

中间我们使用了 JavaScript 的正则匹配和字符处理,做了一些字符拼接,得到新的路径 newPath 变量,最后使用 context.Put("_ctx.request.path",newPath) 更新网关请求的路径信息,从而实现查询条件里面的参数替换。

有关网关内置上下文的变量列表,请访问 Request Context

定义网关

接下来,创建一个网关配置,并使用 javascript 过滤器调用该脚本,如下:

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 10000
    network:
      binding: 0.0.0.0:8000

flow:
  - name: default_flow
    filter:
      - dump:
          context:
            - _ctx.request.path
      - javascript:
          file: index_path_rewrite.js
      - dump:
          context:
          - _ctx.request.path
      - elasticsearch:
          elasticsearch: dev
router:
  - name: my_router
    default_flow: default_flow

elasticsearch:
- name: dev
  enabled: true
  schema: http
  hosts:
    - 192.168.3.188:9206

上面的例子中,使用了一个 javascript 过滤器,并且指定了加载的脚本文件为 index_path_rewrite.js,并使用了两个 dump 过滤器来输出脚本运行前后的路径信息,最后再使用一个 elasticsearch 过滤器来转发请求给 Elasticsearch 进行查询。

启动网关

我们启动网关测试一下,如下:

➜  gateway ✗ ./bin/gateway
   ___   _   _____  __  __    __  _
  / _ \ /_\ /__   \/__\/ / /\ \ \/_\ /\_/\
 / /_\///_\\  / /\/_\  \ \/  \/ //_\\\_ _/
/ /_\\/  _  \/ / //__   \  /\  /  _  \/ \
\____/\_/ \_/\/  \__/    \/  \/\_/ \_/\_/

[GATEWAY] A light-weight, powerful and high-performance elasticsearch gateway.
[GATEWAY] 1.0.0_SNAPSHOT, 2022-04-18 07:11:09, 2023-12-31 10:10:10, 8062c4bc6e57a3fefcce71c0628d2d4141e46953
[04-19 11:41:29] [INF] [app.go:174] initializing gateway.
[04-19 11:41:29] [INF] [app.go:175] using config: /Users/medcl/go/src/infini.sh/gateway/gateway.yml.
[04-19 11:41:29] [INF] [instance.go:72] workspace: /Users/medcl/go/src/infini.sh/gateway/data/gateway/nodes/c9bpg0ai4h931o4ngs3g
[04-19 11:41:29] [INF] [app.go:283] gateway is up and running now.
[04-19 11:41:30] [INF] [api.go:262] api listen at: http://0.0.0.0:2900
[04-19 11:41:30] [INF] [entry.go:312] entry [my_es_entry] listen at: http://0.0.0.0:8000
[04-19 11:41:30] [INF] [module.go:116] all modules are started
[04-19 11:41:30] [INF] [actions.go:349] elasticsearch [dev] is available

执行测试

运行下面的查询来验证查询结果,如下:

curl localhost:8000/abc,efg/_search

可以看到网关通过 dump 过滤器输出的调试信息:

---- DUMPING CONTEXT ----
_ctx.request.path  :  /abc,efg/_search
---- DUMPING CONTEXT ----
_ctx.request.path  :  /cluster01:abc,cluster02:abc,cluster01:efg,cluster02:efg/_search

查询条件按照我们的需求进行了改写,Nice!

重写 DSL 查询语句

好吧,我们刚刚只是修改了查询的索引而已,那么查询请求的 DSL 呢?行不行?

那自然是可以的嘛,瞧下面的例子:

function process(context) {
    var originalDSL = context.Get("_ctx.request.body");
    if (originalDSL.length >0){
        var jsonObj=JSON.parse(originalDSL);
        jsonObj.size=123;
        jsonObj.aggs= {
            "test1": {
                "terms": {
                    "field": "abc",
                        "size": 10
                }
            }
        }
        context.Put("_ctx.request.body",JSON.stringify(jsonObj));
    }
}

先是获取查询请求,然后转换成 JSON 对象,之后任意修改查询对象就行了,保存回去,搞掂。

测试一下:

 curl -XPOST   localhost:8000/abc,efg/_search -d'{"query":{}}'

输出:

---- DUMPING CONTEXT ----
_ctx.request.path  :  /abc,efg/_search
_ctx.request.body  :  {"query":{}}
[04-19 18:14:24] [INF] [reverseproxy.go:255] elasticsearch [dev] hosts: [] => [192.168.3.188:9206]
---- DUMPING CONTEXT ----
_ctx.request.path  :  /abc,efg/_search
_ctx.request.body  :  {"query":{},"size":123,"aggs":{"test1":{"terms":{"field":"abc","size":10}}}}

是不是感觉解锁了新的世界?

结论

通过使用 Javascript 脚本过滤器,我们可以非常灵活的进行复杂逻辑的操作来满足我们的业务需求。

标签:网关,ctx,JavaScript,request,查询,改写,go,path,gateway
From: https://www.cnblogs.com/infinilabs/p/17561880.html

相关文章

  • MySQL(十五)分析优化器的查询计划:Trace
    1MySQL(十五)分析优化器的查询计划:Trace​ OPTIMIZER_TRACE是mysql5.6引入的一项追踪功能,它可以追踪优化器做出的各种决策(比如访问表的方法、各种开销计算和各种转换等等),并将结果记录到表INFORMATION_SCHEMA.OPTIMIZER_TRACE表中。​ Trace功能默认是关闭的,需要开启trace,设置JS......
  • hive sql 查询 所有表 行数
    HiveSQL查询所有表行数ApacheHive是一个基于Hadoop的数据仓库基础架构,它提供了一种类似于SQL的查询语言,称为HiveSQL。在Hive中,我们可以使用HiveSQL查询和处理大规模的结构化和半结构化数据。本文将介绍如何使用HiveSQL查询所有表的行数。Hive中的表在Hive中,表是数据的逻辑......
  • EF Core Like 模糊查询
    在EFCore中可用EF.Functions.Like()、StartWith、Contains、EndsWith实现模糊查询 EF.Functions.Like() 在EntityFrameworkCore2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在LINQ查询中直接调用。query=query.Where(d=>EF.Fun......
  • Mysql基础4-数据查询
    一、DQL介绍DQL全称:DataQueryLanguage(数据查询语言),用来查询数据库中表的记录。关键字:select 二、DQL语法select字段列表from表名列表where条件列表groupby分组字段列表having分组后条件列表orderby排序字段列表limit分页参数注意:本章......
  • java mongodb查询忽略大小写
    实现JavaMongoDB查询忽略大小写概述在使用Java与MongoDB进行数据交互时,有时我们需要执行不区分大小写的查询操作。本文将指导你如何在Java中实现忽略大小写的MongoDB查询。前提条件在开始之前,确保已经安装并配置好了Java开发环境和MongoDB数据库。流程下面是实现JavaMongoD......
  • GB28181设备接入侧录像查询和录像下载技术探究之实时录像
    技术背景我们在对接GB28181设备接入侧的时候,除了常规实时音视频按需上传外,还有个重要的功能,就是本地实时录像,录像后的数据,在执法记录仪等前端设备留底,然后,到工作站拷贝到专门的平台。本文探讨的是,基于GB28181设备接入更进一步的处理:录像查询和录像下载,本文以我们Android平台开发的G......
  • JavaScript
    一、什么是JavaScript?1.JavaScript(简称:JS)是一门跨平台、面向对象的脚本语言。是用来控制网页行为的,它能使网页可交互;2.JavaScript和Java是完全不同的语言,不论是概念还是设计。但是基础语法类似;3.JavaScript在1995年由BrendanEich发明,并于1997年成为ECMA标准;4.ECMAScript......
  • Elasticseach 的查询缓存
    关于 Elasticsearch 的查询缓存,你想知道的都在这里原文地址Elasticsearch中有多种查询缓存,当一个查询请求执行后,他可能会被缓存下来,但是哪些查询会被缓存,哪些不会缓存,缓存了什么内容,什么时候失效,手册中并没有很系统的阐述,并且文档中也存在一些疑点,导致整个查询缓存体系容易让......
  • mysql 查询存储过程调用日志
    如何实现MySQL查询存储过程调用日志作为一名经验丰富的开发者,我将在下面的文章中向你介绍如何实现MySQL查询存储过程调用日志。首先,让我们来了解一下整个流程,然后逐步介绍每一步需要做的事情和相应的代码。流程概述下面是实现MySQL查询存储过程调用日志的整体流程:步骤......
  • mysql 查询blob字段
    如何实现“mysql查询blob字段”概述在MySQL数据库中,BLOB字段是用于存储二进制数据的数据类型,包括图片、音频、视频等。本文将教会你如何通过MySQL查询BLOB字段的值。流程下面是实现“mysql查询blob字段”的流程:步骤描述1连接到MySQL数据库2创建一个查询语句3......