Преглед изворни кода

docs: translate the commit files in PR func #757

ican_do_it пре 4 година
родитељ
комит
d9b6e31d01

+ 58 - 50
docs/en_US/extension/external_func.md

@@ -1,27 +1,28 @@
-# 外部函数
+# External Function
 
 
-外部函数通过配置的方式,将已有的服务映射成 Kuiper SQL 函数。运行使用外部函数的规则时,Kuiper 将根据配置,对数据输入输出进行转换,并调用对应的服务。
+External functions map existing services to Kuiper SQL functions through configuration. When running the rules that use external functions, Kuiper will convert data input and output according to the configuration, and call the corresponding service.
 
 
-## 配置
+## Configuration
 
 
-外部函数的配置文件为 json 格式。通常包括两个部分:
-- json 文件,用于描述服务的信息。文件将保存为 Kuiper 中服务的名字。
-- schema 文件,用于描述服务 API 接口。包括服务包含的 API 名字,输入输出参数类型等。目前仅支持 [protobuf 类型](https://developers.google.com/protocol-buffers) 。
+The configuration file of the external function is in json format, which usually consists of two parts:
 
 
-json 配置文件包括以下两个部分:
+- JSON file, used to describes the information of the service. The file will be saved as the name of the service in Kuiper.
+- Schema file, used to  describes the service API interface, including the name of the API included in the service,, input and output parameter type. Currently only [protobuf type](https://developers.google.com/protocol-buffers) is supported.
 
 
-- about: 用于描述服务的元信息,包括作者,详细描述,帮助文档 url 等。详细用法请参考下面的范例。
-- interfaces: 用于定义一组服务接口。同一个服务器提供的服务往往具有相同的服务地址,可作为一个服务接口。每一个服务接口包含下列属性:
-    - protocol: 服务采用的协议。目前支持 "grpc", "rest" 和 "msgpack-rpc"
-    - adddress: 服务地址,必须为 url。例如,典型 rpc 服务地址:"tcp://localhost:50000" 或者 http 服务地址 "https://localhost:8000"。
-    - schemaType: 服务描述文件类型。目前仅支持 "protobuf"。
-    - schemaFile: 服务描述文件,目前仅支持 proto 文件。rest 和 msgpack 服务也需要采用 proto 描述。
-    - functions: 函数映射数组,用于将 schema 里定义的服务映射到 SQL 函数。主要用于提供函数别名,例如 `{"name":"helloFromMsgpack","serviceName":"SayHello"}` 将服务定义中的 SayHello 服务映射为 SQL 函数 helloFromMsgpack 。未做映射的函数,其定义的服务以原名作为 SQL 函数名。
-    - options: 服务接口选项。不同的服务类型有不同的选项。其中, rest 服务可配置的选项包括:
-        - headers: 配置 http 头
-        - insecureSkipVerify: 是否跳过 https 安全检查
-    
-假设我们有服务名为 'sample',则可定义其名为 sample.json 的服务定义文件如下:
+The json configuration file includes the following two parts:
+
+- about: Used to describe the Meta-information of service, including author, detailed description, help document url, etc. For detailed usage, please refer to the example below.
+- interfaces: Used to define a set of service interfaces. Services provided by the same server often have the same service address and can be used as a service interface. Each service interface contains the following attributes:
+    - protocol: The protocol used by the service. "grpc", "rest" and "msgpack-rpc" are supported currently.
+    - address: Service address, which must be url. For example, typical rpc service address: "tcp://localhost:50000" or http service address "https://localhost:8000".
+    - schemaType: The type of service description file. Only "protobuf" is supported currently .
+    - schemaFile: service description file, currently only proto file is supported. The rest and msgpack services also need to be described in proto.
+    - functions: function mapping array, used to map the services defined in the schema to SQL functions. It is mainly used to provide function aliases. For example,`{"name":"helloFromMsgpack","serviceName":"SayHello"}` can map the SayHello service in the service definition to the SQL function helloFromMsgpack. For unmapped functions, the defined service uses the original name as the SQL function name.
+    - options: Service interface options. Different service types have different options. Among them, the configurable options of rest service include:
+      - headers: configure HTTP headers
+      - insecureSkipVerify: whether to skip the HTTPS security check
+
+Assuming we have a service named 'sample', we can define a service definition file named sample.json as follows:
 
 
 ```json
 ```json
 {
 {
@@ -86,12 +87,13 @@ json 配置文件包括以下两个部分:
 }
 }
 ```
 ```
 
 
-该文件定义了 sample 服务,其中包含 3 个服务接口的调用信息:
-- trueno: grpc 服务
-- tsrest: rest 服务
-- tsrpc:msgpack-rpc 服务
+This file defines the sample service, which contains the call information of 3 service interfaces:
+
+- trueno: grpc service
+- tsrest: rest service
+- tsrpc: msgpack-rpc service
 
 
-每个服务接口提供的服务由其对应的 schema 文件定义。以 tsrest 为例,其 schema 文件为 tsrest.proto,定义如下:
+The service provided by each service interface is defined by its corresponding schema file. Taking tsrest as an example, its schema file is tsrest.proto, which is defined as follows:
 
 
 ```protobuf
 ```protobuf
 syntax = "proto3";
 syntax = "proto3";
@@ -115,29 +117,34 @@ message ObjectDetectionResponse {
 }
 }
 ```
 ```
 
 
-该文件定义了 tsrest 服务接口提供了一个服务 object_detection, 其输入,输出的格式也通过 protobuf 的格式进行了定义。
+This file defines the tsrest service interface to provide a service object_detection, and its input and output formats are also defined by the protobuf format.
+
+Protobuf uses proto3 format. Please refer to [proto3-spec](https://developers.google.com/protocol-buffers/docs/reference/proto3-spec) for detailed format.
+
+### Limitation
 
 
-Protobuf 采用 proto3 格式,详细格式请参考 [proto3-spec](https://developers.google.com/protocol-buffers/docs/reference/proto3-spec) 。
+Since REST and msgpack-rpc are not natively defined by protobuf, there are some  limitations when using them.
 
 
-### 限制
+The REST service is **POST** by default currently, and the transmission format is json. In the defined protobuf:
 
 
-由于 REST 和 msgpack-rpc 并非原生采用 protobuf 定义,因此其使用有一些限制。
+- The input and output format cannot be a basic type, and it must be message
 
 
-REST 服务目前默认为 **POST**,且传输格式为 json。定义的protobuf 中:
-- 输入和输出格式不能为基本类型,必须为 message
+The msgpack-rpc service has the following limitation:
+- Input can not be empty
 
 
-msgpack-rpc 服务有以下限制:
-- 输入不能为空
+## Registration and Management
 
 
-## 注册和管理
+External functions need to be registered before being used. There are two ways to register:
 
 
-外部函数需要注册后才能使用。其注册方法有两种:
-- 放置在配置文件夹
-- 通过 REST API 动态注册。
+- Placed in the configuration folder
+- Dynamic registration via REST API.
+
+When Kuiper is started, it will read and register the external service configuration file in the configuration folder *etc/services*. Before starting, users can put the configuration file into the configuration folder according to the following rules:
+
+1. The file name must be *$service name$.json*. For example, *sample.json* will be registered as a sample service.
+
+2. The Schema file used must be placed in the schema folder. The directory structure is similar to:
 
 
-Kuiper 启动时,会读取配置文件夹 *etc/services* 里的外部服务配置文件并注册。用户可在启动之前,将配置文件遵循如下规则放入配置文件夹:
-1. 文件名必须为 *$服务名$.json*。例如,*sample.json* 会注册为 sample 服务。
-2. 使用的 Schema 文件必须放入 schema 文件夹。其目录结构类似为:
    ```
    ```
    etc
    etc
      services
      services
@@ -149,28 +156,29 @@ Kuiper 启动时,会读取配置文件夹 *etc/services* 里的外部服务配
        other.json
        other.json
        ...
        ...
    ```
    ```
-注意:Kuiper 启动之后,修改配置文件**不能**自动载入系统。需要动态更新时,请使用 REST 服务。
+   Note: After Kuiper is started, it **cannot** automatically load the system by modifying the configuration file. If you need to update dynamically, please use the REST service.
 
 
-服务的动态注册和管理,请参考[外部服务管理 API](../restapi/services.md)。
+For dynamic registration and management of services, please refer to [External Service Management API](../restapi/services.md).
 
 
-## 使用
+## Usage
 
 
-服务注册之后,其中定义的所有函数都可以在规则中使用。以上文 sample.json 中定义的 rest 服务函数 object_detection 为例,在 functions 中,映射为 objectDetection 函数。因此,调用该函数的 SQL 为:
+After the service is registered, all functions defined in it can be used in rules. Taking the rest service function object_detection defined in sample.json above as an example, it is mapped to the objectDetection function in functions. Therefore, the SQL to call this function is:
 
 
 ```SQL
 ```SQL
 SELECT objectDetection(cmd, img) from comandStream
 SELECT objectDetection(cmd, img) from comandStream
 ```
 ```
 
 
-调用前,需要确保 REST 服务运行于 *http://localhost:8090* 且其中有 API *http://localhost:8090/object_detection* 。
+Before calling the function, you need to make sure that the REST service is running on *http://localhost:8090* and there is an API *http://localhost:8090/object_detection* in it.
+
+### Parameter expansion
 
 
-### 参数展开
+In the ptoto file, the general parameters are in message type. When being mapped to Kuiper, its parameters can be received in two situations:
 
 
-ptoto 文件中,一般参数为 message 类型。映射到 Kuiper 中,其参数可接收两种情况:
+1. If the parameters are not expanded, they must be in struct type when being passed in.
+2. If the parameters are expanded, multiple parameters can be passed in according to the order defined in the message.
 
 
-1. 参数不展开,传入的必须为 struct 类型
-2. 参数展开,按照 message 中定义的顺序,传入多个参数
+In the above example, objectDetection receives a message parameter.
 
 
-在上面的例子中,objectDetection 接收一个 message 参数。
 ```protobuf
 ```protobuf
 message ObjectDetectionRequest {
 message ObjectDetectionRequest {
   string cmd = 1;
   string cmd = 1;
@@ -178,4 +186,4 @@ message ObjectDetectionRequest {
 }
 }
 ```
 ```
 
 
-在 Kuiper 中,用户可传入整个 struct 作为参数,也可以传入两个 string 参数,分别作为 cmd 和 base64_img。
+In Kuiper, users can pass in the entire struct as a parameter, or pass in two string parameters as cmd and base64_img respectively.

+ 36 - 93
docs/en_US/extension/overview.md

@@ -1,67 +1,47 @@
-# Extensions
+# Extension
 
 
-Kuiper allows user to customize the different kinds of extensions.  
-
-- The source extension is used for extending different stream source, such as consuming data from other message brokers. Kuiper has built-in source support for [MQTT broker](../rules/sources/mqtt.md).
-- Sink/Action extension is used for extending pub/push data to different targets, such as database, other message system, web interfaces or file systems. Built-in action support in Kuiper, see [MQTT](../rules/sinks/mqtt.md) & [log files](../rules/sinks/logs.md).
-- Functions extension allows user to extend different functions that used in SQL. Built-in functions supported in Kuiper, see [functions](../sqls/built-in_functions.md).
-
-Kuiper extensions are based on golang plugin system. The general steps to make extensions are:
-1. Create the plugin package that implements required source, sink or function interface.
-2. Compile the plugin into a _.so_ file, and put it into sources or sinks or functions folder under _plugins_ folder.
-
-Currently golang plugins are only supported on Linux and macOS which poses the same limitation for Kuiper extensions.
-
-## Naming
-
-We recommend plugin name to be camel case. Notice that, there are some restrictions for the names:
-1. The name of the export symbol of the plugin should be camel case with an **upper case first letter**. It must be the same as the plugin name except the first letter. For example, plugin name _file_ must export a symbol _File_.
-2. The name of _.so_ file must be the same as the export symbol name or the plugin name. For example, _MySource.so_ or _mySink.so_.
+Kuiper allows users to customize extension to support more functions. Users can write plugins for extension. They can also extend functions in SQL through configuration to call existing external REST or RPC services.
 
 
-### Version
+Extension by the use of plugin is more complex and requires users to write code and compile by themselves, which has a certain development cost. The scenarios used include:
 
 
-The user can **optionally** add a version string to the name of _.so_ to help identify the version of the plugin. The version can be then retrieved through describe CLI command or REST API. The naming convention is to add a version string to the name after _@_. The version can be any string. If the version string starts with "v", the "v" will be ignored in the return result. Below are some typical examples.
+- Need to extend the source or sink
+- With high performance requirements
 
 
-- _MySource@v1.0.0.so_ : version is 1.0.0
-- _MySource@20200331.so_:  version is 20200331
+Extension by the use of external function requires only configuration, but it needs to be called through the network, which has a certain performance loss. The scenarios used include:
 
 
-If multiple versions of plugins with the same name in place, only the latest version(ordered by the version string) will be taken effect.
+- Call existing services, such as AI services provided by REST or grpc
+- Services that require flexible deployment
 
 
-## Setup the plugin developing environment
-It is required to build the plugin with exactly the same version of dependencies. And the plugin must implement interfaces exported by Kuiper, so the Kuiper project must be in the gopath. 
+## Plugin extension
 
 
-A typical environment for developing plugins is to put the plugin and Kuiper in the same project. To set it up:
-1. Clone Kuiper project.
-2. Create the plugin implementation file inside plugins/sources or plugin/sinks or plugin/functions according to what extension type is developing.
-3. Build the file as plugin into the same folder. The build command is typically like:
-```bash
-go build -trimpath --buildmode=plugin -o plugins/sources/MySource.so plugins/sources/my_source.go
-```
+Kuiper allows user to customize the different kinds of extensions.  
 
 
-Notice that, the `-trimpath` build flag is required if using the prebuilte kuiper or kuiper docker image because the kuiperd is also built with the flag to improve build reproducibility.
+- The source extension is used for extending different stream source, such as consuming data from other message brokers. Kuiper has built-in source support for [MQTT broker](../rules/sources/mqtt.md).
+- Sink/Action extension is used for extending pub/push data to different targets, such as database, other message system, web interfaces or file systems. Built-in action is supported in Kuiper, see [MQTT](../rules/sinks/mqtt.md) & [log files](../rules/sinks/logs.md).
+- Functions extension allows user to extend different functions that used in SQL. Built-in functions is supported in Kuiper, see [functions](../sqls/built-in_functions.md).
 
 
-### Plugin development
-The development of plugins is to implement a specific interface according to the plugin type and export the implementation with a specific name. There are two types of exported symbol supported:
+Please read the following to learn how to implement different extensions.
 
 
-1. Export a constructor function: Kuiper will use the constructor function to create a new instance of the plugin implementation for each load. So each rule will have one instance of the plugin and each instance will be isolated from others. This is the recommended way.
+- [Source extension](./source.md)
+- [Sink/Action extension](./sink.md)
+- [Function extension](./function.md)
 
 
-2. Export an instance: Kuiper will use the instance as singleton for all plugin load. So all rules will share the same instance. For such implementation, the developer will need to handle the shared states to avoid any potential multi-thread problems. This mode is recommended where there are no shared states and the performance is critical. Especially, function extension is usually functional without internal state which is suitable for this mode.
+## Naming
 
 
-Please read below for how to realize the different extensions.
+We recommend plugin name to be camel case. Notice that, there are some restrictions for the names:
 
 
-- [Source extension](source.md)
-- [Sink/Action extension](sink.md)
-- [Function extension](function.md)
+1. The name of the export symbol of the plugin should be camel case with an **upper case first letter**. It must be the same as the plugin name except the first letter. For example, plugin name _file_ must export a export symbol name _File_ .
+2. The name of _.so_ file must be the same as the export symbol name or the plugin name. For example, _MySource.so_ or _mySink.so_.
 
 
-### State Storage
+### State storage
 
 
-Kuiper extensions export a key value state storage interface for Source/Sink/Function through the context.
+Kuiper extension exposes a key value state storage interface through the context parameter, which can be used for all types of extensions, including Source/Sink/Function extensions.
 
 
-States are key-value pairs, where the key is a string and the value is arbitrary data. Keys are scoped to an individual extension.
+States are key-value pairs, where the key is a string and the value is arbitrary data. Keys are scoped the to current extended instance.
 
 
-You can access states within extensions using the putState, getState, incrCounter, getCounter and deleteState calls on the context object.
+Users can access the state storage through the context object. State-related methods include putState, getState, incrCounter, getCounter and deleteState.
 
 
-Below is an example of a function extension to access states. It will record the accumulate word count across a range of function calls.
+Below is an example of a function extension to access states. This function will count the number of words passed in and save the cumulative number in the state.
 
 
 ```go
 ```go
 func (f *accumulateWordCountFunc) Exec(args []interface{}, ctx api.FunctionContext) (interface{}, bool) {
 func (f *accumulateWordCountFunc) Exec(args []interface{}, ctx api.FunctionContext) (interface{}, bool) {
@@ -78,58 +58,21 @@ func (f *accumulateWordCountFunc) Exec(args []interface{}, ctx api.FunctionConte
 }
 }
 ```
 ```
 
 
-The state storage API includes
+### Runtime dependencies
+
+Some plugin may need to access dependencies in the file system. Those files is put under {{kuiperPath}}/etc/{{pluginType}}/{{pluginName}} directory. When packaging the plugin, put those files in [etc directory](../restapi/plugins.md#plugin-file-format). After installation, they will be moved to the recommended place.
+
+In the plugin source code, developers can access the dependencies of file system by getting the Kuiper root path from the context:
 
 
 ```go
 ```go
-/**
- * Increase the builtin distributed counter referred by key
- * @param key The name of the key
- * @param amount The amount to be incremented
- * @return error if any 
- */
-IncrCounter(key string, amount int) error
-/**
- * Retrieve the counter value by key
- * @param key The name of the key
- * @return the counter value
- * @return error if any 
- */
-GetCounter(key string) (int, error)
-/**
- * Set or update the state value for the key.
- *
- * @param key name of the key
- * @param value state value of the key
- * @return error if any 
- */
-PutState(key string, value interface{}) error
-/**
- * Retrieve the state value for the key.
- *
- * @param key name of the key
- * @return the state value
- * @return error if any 
- */
-GetState(key string) (interface{}, error)
-/**
- * Delete the state value for the key.
- *
- * @param key name of the key
- * @return error if any 
- */
-DeleteState(key string) error
+ctx.GetRootPath()
 ```
 ```
 
 
-#### State data type
-
-The state can be any type. If the rule [checkpoint mechanism](../rules/state_and_fault_tolerance.md) is enabled, the state will be serialized by [golang gob](https://golang.org/pkg/encoding/gob/). So it is required to be gob compatibile. For custom data type, register the type by ``gob.Register(value interface{})`` .
+## External function extension
 
 
-### Runtime dependencies
+A configuration method is provided that Kuiper can use SQL to directly call external services in a functional manner, including various rpc services, http services, and so on. This method will greatly improve the ease of Kuiper extensions. External functions will be used as a supplement to the plugin system, and plugins are only recommended for high performance requirements.
 
 
-Some plugin may need to access dependencies in the file system. It is recommended to put those files under {{kuiperPath}}/etc/{{pluginType}}/{{pluginName}} directory. When packaging the plugin, put those files in [etc directory](../restapi/plugins.md#plugin-file-format). After installation, they will be moved to the recommended place.
+Take the getFeature function as an example, and suppose an AI service provides getFeature service based on grpc. After Kuiper is configured, you can use the method of `SELECT getFeature(self) from demo` to call the AI service without customizing the plugin.
 
 
-In the plugin source code, developers can access the file system by getting the Kuiper root path from the context:
+For detailed configuration method, please refer to [External function](external_func.md).
 
 
-```go
-ctx.GetRootPath()
-```

+ 27 - 27
docs/en_US/restapi/services.md

@@ -1,13 +1,13 @@
-Kuiper REST api 允许您管理外部服务,例如注册、删除和列出服务,列出外部函数等。
+Kuiper REST api allows you to manage external services, such as registering, deleting and listing services, listing external functions.
 
 
-## 注册外部服务
+## Register external services
 
 
-该API接受JSON内容以创建新的外部服务。 
+This API accepts JSON content to create new external services.
 
 
 ```shell
 ```shell
 POST http://localhost:9081/services
 POST http://localhost:9081/services
 ```
 ```
-文件在http服务器上时的请求示例:
+An example of a request for a file on an HTTP server:
 
 
 ```json
 ```json
 {
 {
@@ -16,7 +16,7 @@ POST http://localhost:9081/services
 }
 }
 ```
 ```
 
 
-文件在Kuiper所在服务器上时的请求示例:
+An example of a request for a file on the Kuiper server:
 ```json
 ```json
 {
 {
   "name":"random",
   "name":"random",
@@ -24,52 +24,52 @@ POST http://localhost:9081/services
 }
 }
 ```
 ```
 
 
-### 参数
+### parameter
 
 
-1. name:外部服务的唯一名称,名称必须与 zip 文件里的服务定义 json 文件完全相同。
-2. file:外部服务文件的 URL。URL 支持 http 和 https 以及 file 模式。当使用 file 模式时,该文件必须在 Kuiper 服务器所在的机器上。它必须是一个 zip 文件,其中包含:与服务名相同的服务描述 json 文件以及其他任意辅助文件。其中,schema 文件必须在 schema 文件夹下。
+1. name: The unique name of the external service, which must be exactly the same as the json file of service definition in the zip file.
+2. file: URL of external service file. URL supports http, https and file modes. When using the file mode, the file must be on the machine where the Kuiper server is located. It must be a zip file, which contains the service description json file with the same name as the service and any other auxiliary files. The schema file must be in the schema folder.
 
 
-### 服务文件格式
-名为 sample.zip 的源的示例 zip 文件
+### Service file format
+A sample zip file of the source named sample.zip
 1. sample.json
 1. sample.json
-2. schema 目录:内部包含服务所用到的一个或多个 schema 文件。例如,sample.proto。
+2. Schema directory: it contains one or more schema files used by the service. For example, sample.proto.
 
 
 
 
-## 显示外部服务
+## Display external services
 
 
-该 API 用于显示服务器中为定义的所有外部服务。
+This API is used to display all external services defined in the server.
 
 
 ```shell
 ```shell
 GET http://localhost:9081/services
 GET http://localhost:9081/services
 ```
 ```
 
 
-响应示例:
+Response example:
 
 
 ```json
 ```json
 ["sample","sample2"]
 ["sample","sample2"]
 ```
 ```
 
 
-## 描述外部服务
+## Describe external services
 
 
-该 API 用于打印外部服务的详细定义。
+This API is used to print detailed definitions of external services.
 
 
 ```shell
 ```shell
 GET http://localhost:9081/plugins/services/{name}
 GET http://localhost:9081/plugins/services/{name}
 ```
 ```
 
 
-路径参数 `name` 是外部服务的名称。
+The path parameter `name` is the name of the external service.
 
 
-## 删除外部服务
+## Delete external services
 
 
-该 API 用于删除外部服务,服务之下定义的所有函数都将被删除。
+This API is used to delete external services, and all functions defined under the service will be deleted.
 
 
 ```shell
 ```shell
 DELETE http://localhost:8080/plugins/services/{name}
 DELETE http://localhost:8080/plugins/services/{name}
 ```
 ```
 
 
-## 更新外部服务
+## Update external services
 
 
-该 API 用于更新外部服务,其参数与服务注册相同。
+This API is used to update external services, and its parameters are the same as that of service registration.
 
 
 ```shell
 ```shell
 PUT http://localhost:9081/services/{name}
 PUT http://localhost:9081/services/{name}
@@ -80,29 +80,29 @@ PUT http://localhost:9081/services/{name}
 }
 }
 ```
 ```
 
 
-## 显示所有外部函数
+## Display all external functions
 
 
-每个服务可包含多个函数。该 API 用于展示所有外部函数的可用于 SQL 的函数名称。
+Each service can contain multiple functions. This API is used to display the names of all external functions that can be used in SQL.
 
 
 ```shell
 ```shell
 GET http://localhost:9081/services/functions
 GET http://localhost:9081/services/functions
 ```
 ```
 
 
-结果样例:
+Result example:
 
 
 ```json
 ```json
 ["func1","func2"]
 ["func1","func2"]
 ```
 ```
 
 
-### 描述外部函数
+### Describe external functions
 
 
-该 API 用于展示定义此外部函数的服务名称。
+This API is used to display the name of the service that defines this external function.
 
 
 ```shell
 ```shell
 GET http://localhost:9081/services/functions/{name}
 GET http://localhost:9081/services/functions/{name}
 ```
 ```
 
 
-结果样例:
+Result example:
 
 
 ```json
 ```json
 {
 {

+ 3 - 1
docs/en_US/sqls/overview.md

@@ -1,8 +1,10 @@
 Kuiper offers a SQL-like query language for performing transformations and computations over streams of events. This document describes the syntax, usage and best practices for the Kuiper query language. 
 Kuiper offers a SQL-like query language for performing transformations and computations over streams of events. This document describes the syntax, usage and best practices for the Kuiper query language. 
 
 
 - [Stream specifications](streams.md)
 - [Stream specifications](streams.md)
-
 - [Query languange element](query_language_elements.md)
 - [Query languange element](query_language_elements.md)
 - [Windows](windows.md)
 - [Windows](windows.md)
 - [Built-in functions](built-in_functions.md)
 - [Built-in functions](built-in_functions.md)
+- Extension
+  - [Plugin extension](../extension/overview.md)
+  - [External service extension](../extension/external_func.md)