apache / incubator-streampark

Make stream processing easier! Easy-to-use streaming application development framework and operation platform.
https://streampark.apache.org/
Apache License 2.0
3.86k stars 996 forks source link

[Feat] Sql autocomplete (I can apply my code solution ) #504

Closed Whojohn closed 2 months ago

Whojohn commented 2 years ago

Feature Request

您的功能诉求是否是跟某个问题相关的? We need Sql autocomplete in StreamX.

StreamX 中没有Sql autocomplete,使用不友好。

你希望的新功能诉求是怎么样的? We are human, we always depends on autocompelete or hits to development. We need auto parser to notice user their sql grammar is not right before running. 开发的时候有自动提示,启动前提示用户 sql 语法哪里错了,可能的值。

您为此有过什么替代方案? Sql client notic and so on . However Sql client notice is not perfect.(ps: I can apply my solution ).

Sql client 的实现(很烂)。HueZeppeline 的挺好用。

辅助文档 我的实现方案(分阶段实现):

第三阶段(not only suggestion) ps: 更大胆一点,把Flink sql 做成数仓。平台封装Sql connector信息,通过特定语法或者是特定条件复用连接(我们的内部实现,这样还能屏蔽掉用户知道物理底层的连接信息,!!!让用户知道连接是一样很丑陋,且不安全的事情!!!)。 比如: show table 显示所有可用的连接信息等等这些特性,并且提示可用表等。

wolfboys commented 2 years ago

good idea! this is a great feature. contribution are welcome

wolfboys commented 2 years ago

This feature has been planned to be v1.2.2, the specific details can be discussed more

Whojohn commented 2 years ago

进度汇报

已经添加对应的测试用例

详细 demo 级别代码见 : https://github.com/Whojohn/flink-sql/blob/main/src/test/java/TestSqlAutoComplete.java

ps: 这个代码的实现应该放在这个仓库的哪个位置?是放在 notepad 里面?需要前端调用后端接口实现(第二阶段实现,必须走后端)。 兼容性的话,spark 其他 sql 都可以透过这个套路实现,第一阶段的实现,不依赖具体的 sql parse。 @wolfboys

wolfboys commented 2 years ago

这是非常棒的特性,你可以继续开发测试,我看了当前提交的,是一个测试用例,得考虑下真正前后端联调情况下的实现,最好能有相关的资料,如设计图,流程图等.在相关功能完善上多考虑一些, 希望你继续加油努力! 我们拭目以待.

Whojohn commented 2 years ago

第一阶段基本完成了

套个 Spring 请求 这功能就完事,安排下前端对接,还有提供下Spring接口放在哪里,有什么特殊要求没有。

该功能特殊依赖:

  1. 一个记录词频的文本。

    https://github.com/Whojohn/flink-sql/blob/main/statistics

1. 为什么要这么实现

Flink sql Client(TableEnvironment.getCompletionHints 实现)

  1. 基于Sql parse做,可以做到语法检测。
  2. 一定的纠错能力,联想。
  1. 对于用户没有写完的语句依旧执行语法检测,导致语法提示,纠错混乱,实际效果不友好。不如在;出现后(用户完成输入)再进行语法检测,输入过程中只提示潜在词更友好。
  2. 性能不好
  3. 需要外部依赖,如:FlinkSpark 等各自的语法解析器包。

FST + 词频实现

  1. 更符合人类的纠错,联想能力,用户在完成输入前,提供人性化的提示,具体效果见测试用例。
  2. 性能好。
  3. 没有外部依赖,不同Sql只需要词频字典即可实现,用户可以自行调整字典,细分字典等实现更加个性化功能。
  1. 词频字典的维护。
  2. 没有语法检测。(第二阶段可以彻底解决该问题,对于输入完成的语句才执行语法检测)
FST+ 词频实现 Flink sql Client实现
性能 10倍的性能,更加顺滑的体验 较慢
维护性 需要额外维护字典 需要依赖Flink Sql parse
扩展性 用户可以自行定制化:如分级提示(比如考虑文中位置,改变函数提示,结构关键字位置) 难以扩展
语法检测 没有
纠错&联想能力 个人认为更好,看测试用例,欢迎大家提出测试用例 不太友好

2. FST 树第一阶段最终功能(暂定,已经实现)

  1. 没有语法检测(语法检测很好做,但是与交换方式是耦合的,建议放到第二阶段做)。
  2. 带有一定的纠错和输入提示。
  3. 输入提示:通过用户输入的前缀,联想所有可能的Sql 关键字,如:Se 联想到 se开头的所有关键字。(PS:HUE还有函数功能的语法和功能提示,这个可以放到前端做。)
  4. 有限纠错:通过引入前序,后序匹配,返回可能值,增强纠错功能。如:arom 能够提示Fromseloct能提示select。纠错的原理在于假定输入错误的不可能同时在第一个和最后一个字符输入错误,即eroa,无法联想到from

3.测试用例

S
arom
form
oelect
sel
seloct
select * f
select * frem
select * from source_tab
select * from source_table whore
select * from source_table where user_i
select * from source_table where user_id = 12 group by 
select * from source_table where user_id = 12 group by substring(
select * from source_table where user_id = 12 group by substring (

TableEnvironment.getCompletionHints 联想结果

[]
[]
[]
[]
[]
[]
[FETCH, FROM]
[]
[default_catalog.default_database.source_table]
[]
[user_id]
[...]
[...]
[...]

FST 实现联想结果 (不带有词频优化)

 [system, symmetric, sum, substring, substitute, submultiset, subclass_origin, ...]
 [from, avg, authorization, at, as, array, are, any, and, always, alter, all,...]]
 [transform, found, fortran, foreign, for, following]
 [select, over, out, others, or, option, open, on, old, of, octets, octet_length,...]]
 [self, select]
 [set, session, server, serializable, sequence, sensitive, self, select, ...]]
 [fusion, function, full, from, free, frac_second, found, for, following, ...]]
 [from, free, frac_second]
 [source]
 [write, wrapper, work, with, window, width_bucket, where, when, week,...]]
 [user_defined_type_schema, user_defined_type_name, user_defined_type_code,...]]
 []
 [substring]
 [()]

FST 实现联想结果词频优化,第一阶段最终形态

[select, source, string, sql, sum, some, second ...]
[as, from, and, array, at, avg, any, all, add, ...]]
[for, following, foreign, found, transform, ...]]
[select, of, or, on, over, object, old, others, ...]]
[select, self]
[select, second, set, search, self, session, ...]]
[from, for, false, float, filter, first, final, ...]]
[from, free, frac_second]
[source]
[where, with, window, more, work, before, when, ...]
[user_defined_type_schema, user_defined_type_name, ...]]
[]
[substring]
[()]
aiwenmo commented 2 years ago

您好,您的 Sql autocomplete 要通过大量的前后端交互来实现吗?对于 B/S 的系统,个人认为这个功能偏前端,前端可以提前加载后台的配置如词典或者元数据,然后具体的提示与补全逻辑可在前端实现,最后通过后台校验语法与逻辑是否可通过。此外在书写的过程中验证和校验的功能其实并不实用,因为不完整的句子一定是无法通过校验的。具体的实现可以参考一下 Dlink 的自定义语法提示与补全与语法和逻辑校验功能。希望此文可以帮助您。

Whojohn commented 2 years ago

您好,您的 Sql autocomplete 要通过大量的前后端交互来实现吗?对于 B/S 的系统,个人认为这个功能偏前端,前端可以提前加载后台的配置如词典或者元数据,然后具体的提示与补全逻辑可在前端实现,最后通过后台校验语法与逻辑是否可通过。此外在书写的过程中验证和校验的功能其实并不实用,因为不完整的句子一定是无法通过校验的。具体的实现可以参考一下 Dlink 的自定义语法提示与补全与语法和逻辑校验功能。希望此文可以帮助您。

的确实现前有些考虑不充分,我们的纠错也是基于词而已(现在版本),之前没了解到monaco现在也能做到元解析,所以把这部分完全放后端(还是关键字解析,我们想要元解析)? 具体没精力调研。假如可以,可以填入,Dlink 的实现吗?一个一个查源码也很累。 调研结果是:跨节点,比如阿里的x6那种交互,语法增强,纠错,特殊屏蔽,涉及到后台的元数据(普通用户不可见元信息,我们内部)都是后端控制的。简单的提示,都走前端。

自动补全调研

调研方向

Zeppeline

Zeppeline : 0.10

Flink : 1.12.7

语法提示 方法提示 udf 上下文提示 输入纠错
支持 不支持(因为后端没有实现。。。只有前端写死的内置方法,偶尔还是不提示) 不支持(show function 可见) 支持(基于关键字提示,做不到hue那种智能识别表,字段等) 没有

语法提示粒度(没有说明文档)

  1. keyword
  2. local

源码解析(底层原理)

Zeppeline 底层是基于前端配合后端来做的,!!!但是Flink所有实现暂时没有实现后端补全逻辑!!!。前端根据字典和用户输入词进行提示

tying -> pass tag button -> websocket-enent.factory -> COMPLETION_LIST event -> http server -> Paragraph.completion -> /FlinkInterpreter.complete

调用链追踪

remoteInterpreter 再次调用 FlinkInterpreter 实现(这样的目的应该是为了共享会话?)

completion:318, RemoteInterpreter (org.apache.zeppelin.interpreter.remote)
completion:271, Paragraph (org.apache.zeppelin.notebook)
completion:900, Note (org.apache.zeppelin.notebook)
completion:968, NotebookService (org.apache.zeppelin.service)
completion:1312, NotebookServer (org.apache.zeppelin.socket)
onMessage:398, NotebookServer (org.apache.zeppelin.socket)
onWebSocketText:58, NotebookSocket (org.apache.zeppelin.socket)
onTextMessage:231, JettyListenerEventDriver (org.eclipse.jetty.websocket.common.events)
messageComplete:69, SimpleTextMessage (org.eclipse.jetty.websocket.common.message)
appendMessage:65, AbstractEventDriver (org.eclipse.jetty.websocket.common.events)
onTextFrame:179, JettyListenerEventDriver (org.eclipse.jetty.websocket.common.events)
incomingFrame:150, AbstractEventDriver (org.eclipse.jetty.websocket.common.events)
incomingFrame:326, WebSocketSession (org.eclipse.jetty.websocket.common)
nextIncomingFrame:147, AbstractExtension (org.eclipse.jetty.websocket.common.extensions)
nextIncomingFrame:112, PerMessageDeflateExtension (org.eclipse.jetty.websocket.common.extensions.compress)
forwardIncoming:168, CompressExtension (org.eclipse.jetty.websocket.common.extensions.compress)
incomingFrame:92, PerMessageDeflateExtension (org.eclipse.jetty.websocket.common.extensions.compress)
incomingFrame:202, ExtensionStack (org.eclipse.jetty.websocket.common.extensions)
notifyFrame:225, Parser (org.eclipse.jetty.websocket.common)
parseSingleFrame:259, Parser (org.eclipse.jetty.websocket.common)
onFillable:459, AbstractWebSocketConnection (org.eclipse.jetty.websocket.common.io)
onFillable:440, AbstractWebSocketConnection (org.eclipse.jetty.websocket.common.io)
succeeded:311, AbstractConnection$ReadCallback (org.eclipse.jetty.io)
fillable:105, FillInterest (org.eclipse.jetty.io)
run:104, ChannelEndPoint$1 (org.eclipse.jetty.io)
runJob:806, QueuedThreadPool (org.eclipse.jetty.util.thread)
run:938, QueuedThreadPool$Runner (org.eclipse.jetty.util.thread)
run:748, Thread (java.lang)

父类: AbstractInterpreter (默认实现是空字符串,sql 就是返回空)

子类:FlinkSqlInterpreter (父类实现)

子孙类:FlinkStreamSqlInterpreter FlinkBatchSqlInterpreter (父类实现)

HUE

体现最好,提供后端和前端提示支持,默认使用前端提示。但是后端增强部分代码不开放( Navigator Optimizer属于商业技术,官方demo中效果最好)。不启用后端增强,应该也必须走后端,因为后端会解析,记录历史的catalog。(估计阿里也是这么实现,跨会话,单个作业的提示。)

智能体现在:

  1. 输入 fr, 自动联想 from tables (能够联想到当前会话所有table)
  2. 输入不符合语法的比如(select xxx from xxx from xxx) 会停止联想
  3. 统计历史表达式,返回表达式联想如日期格式转换

docker compose 信息:https://gethue.com/blog/tutorial-query-live-data-stream-with-flink-sql/

官方demo :https://demo.gethue.com/hue/accounts/login?next=/

虽然这个是功能预览版本,基本功能应该跟正式发布版本相差不大

hue: 4.9 (官方 demo & docker)

语法提示 方法提示 udf 上下文提示 输入纠错
支持 支持 支持 支持(基于语法实现,并且通过后端解析,提供基于词频,上下文提示,性能提示等增强功能) 没有

语法提示粒度(带有文档提示,前端,后端都提供分类接口,后端结果会影响前端提示优先级)

  1. keywrod

  2. column(表属性列)

  3. 方法 (udf )

  4. table

  5. popular (基于历史输入的提示,支持 join 表,函数提示)

源码解析(底层原理)

reference:

https://github.com/cloudera/hue/blob/master/docs/designs/apache_flink.md (flink autocomplete document)

https://github.com/romainr/flink-sql-gateway/tree/master/docs/demo

https://docs.gethue.com/developer/api/rest/ (autocomplete)

https://docs.gethue.com/developer/components/ (autocomplete js)

https://gethue.com/hue-4-sql-editor-improvements/

具体信息见官方文档即可,简单查看过代码,发现后端增强来自于Navigator Optimizer 这个商业功能,依赖后端解析。不源码追踪还有个重要原因是 hue 依赖 flink gateway,配置很麻烦

aiwenmo commented 2 years ago

Dlink

Dlink : 0.4.0

Flink : 1.11、1.12、1.13、1.14

语法提示 | 方法提示 | udf | 上下文提示 | 输入纠错 -- | -- | -- | -- | -- 支持,且支持自定义扩展及联想 | 支持,且支持自定义扩展及联想 | 支持,且支持自定义扩展及联想 | 支持,联想 | 支持,手动触发
  1. 由于 Dlink 的提示与补全原理使用了自定义规则的方式,所以满足所有的可能性,不过需要手动扩展规则。

  2. Dlink 提供了更加专业的 sql 交互,可在线查询,使 FlinkSQL 的开发和使用更接近 Navicat、DataGrip 等。

源码解析(底层原理)

Dlink 底层也是基于前端配合后端来做的。后端维护规则,前端根据规则和用户输入词进行联想与补全。

欢迎补充~