67 Commits

Author SHA1 Message Date
superhero
0d5da763b3 Merge pull request #2234 from beat4ocean/master
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
[Fix][headless-fe] Error when copying access token
2025-04-27 09:42:42 +08:00
beat4ocean
d1b4863a27 [Fix][headless-fe] Error when copying access token 2025-04-26 10:31:26 +08:00
supersonicbi
dce9a8a58c (fix)(chat)Fix NPE in getParseInfo.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-25 20:41:04 +08:00
jerryjzhang
fbf048cb00 (fix)(headless)Fix show type and retrieve issues.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-21 14:41:31 +08:00
jerryjzhang
48a8f69cca [fix][heaadless]Use columnName as fieldName.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-15 21:25:04 +08:00
jerryjzhang
ecdf65da3e (fix)(headless)Fix bizName and name NPE issue.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-04-14 21:09:37 +08:00
poncheen
5585b9e222 Fix/ts errors in fe (#2218)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-11 20:58:35 +08:00
Antgeek
97710a90c4 (improve)(benchmark) improve benchmark, add analysis of parsing results (#2215)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-10 08:57:25 +08:00
jerryjzhang
0ab7643299 [fix][heaadless]Optimize logic of determine number types.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-04-10 00:25:56 +08:00
Antgeek
d2aa73b85e (fix)(headless) fix ModelCreateForm.tsx error (#2214)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-04-08 20:49:37 +08:00
chixiaopao
8828964e53 (fix)(headless) fix dfs NullPointerException when model is null. (#2212)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-04-07 20:55:41 +08:00
beat4ocean
b188da8595 [Fix] cannot save schema-mapping and semantic-S2SQL modification. (#2210)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-04-07 08:57:06 +08:00
jerryjzhang
2e7ba468c9 (fix)(chat)Return chat id when creating new one.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-05 18:43:16 +08:00
naimehao
d26c9180ed fix headless-core (#2208)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-04 08:19:20 +08:00
Antgeek
ca96aa725d (fix)(headless) method getProperties maybe cause NullPointerException (#2202)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-04-02 17:48:41 +08:00
kino
614917ba76 [Improvement] Reduce Docker image size #2204 (#2205) 2025-04-02 17:26:19 +08:00
jerryjzhang
1fed8ca4d9 (fix)(headless)Fix hash code issue of MetricSchemaResp and DimensionSchemaResp.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-30 07:20:07 +08:00
beat4ocean
232a202275 [Improvement] Upgrade dependencies and fix vulnerabilities. (#2190)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-28 09:07:49 +08:00
jerryjzhang
791c493a6a Merge remote-tracking branch 'origin/master'
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-28 01:19:01 +08:00
jerryjzhang
f9d4ce2128 [fix][auth]Fix last_login of user not being selected. 2025-03-28 01:18:48 +08:00
coosir
8abfc923a0 (fix)(supersonic-fe) support needMultiply100 for bar chart to show correct percentage value (#2189)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-26 10:11:52 +08:00
beat4ocean
e6598a79bb [Fix] Fix MetricServiceImpl and PromptHelper NPE issue (#2191)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-25 13:34:35 +08:00
jerryjzhang
d2a43a99c8 (feature)(headless)Support offset clause in struct query.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-23 14:30:56 +08:00
iridescentpeo
db8f340e2d 修复同一模型被多个数据集引用时: (#2183) 2025-03-23 14:14:08 +08:00
Kun Gu
2e81b190a4 将utf8的编码修改为utf8mb4,解决部分因为字符出现的BUG (#2182)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-21 22:54:34 +08:00
guilinlewis
81cd60d2da fix-common-因缓存无法存记忆 (#2181) 2025-03-21 22:30:38 +08:00
jerryjzhang
3ffc8c3d9e (improvement)(headless)Make rule-based corrector switchable. 2025-03-21 22:10:41 +08:00
jerryjzhang
18db24c011 (fix)(headless)Fix issue of dimension value not replaced by alias. #2074 2025-03-21 21:49:47 +08:00
Hwting
cd698ac367 Update docker-compose.yml (#2184) 2025-03-21 21:38:29 +08:00
jerryjzhang
58b640b087 (fix)(headless)Fix issue of dimension value not replaced by alias. 2025-03-21 21:33:40 +08:00
jerryjzhang
1f28aaeaed (feature)(auth)Add last_login field to User. 2025-03-21 20:58:59 +08:00
jerryjzhang
35b835172b (fix)(headless)Updating dimension should update modelDetail as well.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-19 10:05:04 +08:00
jerryjzhang
1c85bcecc5 Merge remote-tracking branch 'origin/master'
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-14 23:11:51 +08:00
jerryjzhang
c3483ae340 (fix)(assembly)Increase minimum heap size to avoid not enough space issue. 2025-03-14 23:11:44 +08:00
williamhliu
a5051c7225 (improvement)(supersonic-fe) remove listColumnsBySql (#2173)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-14 08:51:37 +08:00
jerryjzhang
12f6cfa42d (fix)(headless)Metric filters do not take effect in struct query.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-13 18:53:13 +08:00
jerryjzhang
4c94f2b816 Merge remote-tracking branch 'origin/master' 2025-03-13 18:52:39 +08:00
jerryjzhang
c81aa5859d (improvement)(headless)Add unit test case for variable if statement. 2025-03-13 18:52:30 +08:00
guilinlewis
21e213fb19 (improvement)(headless | chat ) 向量数据被重置后,记忆不会再次添加到向量数据库 (#2164)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-12 22:19:51 +08:00
jerryjzhang
f67bf3eeac (fix)(chat)Fix bug in creating chat model. 2025-03-12 16:47:40 +08:00
jerryjzhang
9d13038599 (fix)(headless)Fix schema corrector in that aliases should not be replaced. 2025-03-12 16:31:43 +08:00
beat4ocean
0c8c2d4804 [fix][headless] Fix issue filterSql is not working. (#2157)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-12 13:53:08 +08:00
williamhliu
f05a4b523c (fix)(supersonic-fe) show tip when register failed and replace icon when login failed and fix metric style issue (#2160) 2025-03-12 08:22:46 +08:00
jerryjzhang
b7369abcca [improvement][docker]Facilitate database configuration when running with docker.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-11 23:14:40 +08:00
jerryjzhang
b40cb13740 (fix)(chat)Should check permission when returning data set tree.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-11 15:32:12 +08:00
williamhliu
6f8cf9853b (fix)(supersonic-fe) fix the issue where there is no prompt when saving the dataset (#2154)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-11 10:36:03 +08:00
williamhliu
75906037ac (fix)(supersonic-fe) fix the issue where there is no prompt when saving the dataset (#2152) 2025-03-11 09:19:22 +08:00
jerryjzhang
b58e041e8d [improvement][chat]Adopt accept pattern to parsers and executors.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-11 00:27:06 +08:00
jerryjzhang
93d585c0d5 [feature][common]Add permission management to chat model. 2025-03-10 23:58:19 +08:00
jerryjzhang
0dbf56d357 [fix][chat]Fix query time cost bug. 2025-03-10 23:21:07 +08:00
zyclove
a3293e6788 fix:java.lang.NullPointerException: Cannot invoke "com.tencent.supersonic.common.pojo.DateConf.getDateField()" because "dateConf" is null (#2142)
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-09 13:44:07 +08:00
jerryjzhang
a99f5985f5 (improvement)(headless)Set fields of model detail when restoring model.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-09 10:58:49 +08:00
jerryjzhang
91243005bc (fix)(launcher)Change join_condition to type text to avoid "value too long for column". 2025-03-09 09:18:29 +08:00
jerryjzhang
a76b5a4300 (improvement)(headless)Add unit to measure. 2025-03-09 09:15:13 +08:00
jerryjzhang
c1f9df963c (improvement)(headless)Add expr to semantic column. 2025-03-09 08:31:48 +08:00
Shaofeng Shi
954aa4eea5 fix: https://github.com/tencentmusic/supersonic/issues/2132 for Trino syntax (#2144)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-08 21:41:35 +08:00
jerryjzhang
33bd0de604 (improvement)(headless)Set fields of model detail when creating model. 2025-03-08 21:16:10 +08:00
jerryjzhang
881d891d70 (license)Update communication email address.
Some checks failed
supersonic CentOS CI / build (21) (push) Has been cancelled
supersonic mac CI / build (21) (push) Has been cancelled
supersonic ubuntu CI / build (21) (push) Has been cancelled
supersonic windows CI / build (21) (push) Has been cancelled
2025-03-06 09:31:51 +08:00
jerryjzhang
d9db455dab (improvement)(headless)Optimize compatibility and robustness in ontology query translation.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-05 20:47:57 +08:00
jerryjzhang
e0dc3fbf1a (improvement)(headless)Optimize compatibility and robustness in ontology query translation.
(improvement)(headless)Optimize compatibility and robustness in ontology query translation.
2025-03-05 17:11:59 +08:00
zyclove
efddf4cacf fix: https://github.com/tencentmusic/supersonic/issues/2132 (#2137) 2025-03-05 14:54:16 +08:00
jerryjzhang
732222ab98 (fix)(headless)Fix database permission check.
(fix)(headless)Fix database permission check.
2025-03-05 14:39:53 +08:00
jerryjzhang
5b994c4f8f (fix)(github)Upgrade actions/cache from 2 to 4. 2025-03-05 12:51:15 +08:00
Dack Wang
5d2ebdf680 (fix)(README) 404 docs link (#2133) 2025-03-05 12:36:56 +08:00
coosir
f1bc18ef65 Update docker-compose.yml (#2127)
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
fix data persistence issue
2025-03-05 08:36:04 +08:00
jerryjzhang
8f361f9932 (improvement)(auth)Use interface in place of impl class.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-04 17:56:41 +08:00
jerryjzhang
f532088e38 (feature)(releaes)Start 1.0.0-SNAPSHOT release.
Some checks are pending
supersonic CentOS CI / build (21) (push) Waiting to run
supersonic mac CI / build (21) (push) Waiting to run
supersonic ubuntu CI / build (21) (push) Waiting to run
supersonic windows CI / build (21) (push) Waiting to run
2025-03-04 10:11:00 +08:00
163 changed files with 1891 additions and 1149 deletions

View File

@@ -11,7 +11,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: quay.io/centos/centos:stream8 # 使用 CentOS Stream 8 容器 image: almalinux:9 # maven >=3.6.3
strategy: strategy:
matrix: matrix:
@@ -28,9 +28,10 @@ jobs:
- name: Reset DNF repositories - name: Reset DNF repositories
run: | run: |
cd /etc/yum.repos.d/ sed -e 's|^mirrorlist=|#mirrorlist=|g' \
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* -e 's|^# baseurl=https://repo.almalinux.org|baseurl=https://mirrors.aliyun.com|g' \
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* /etc/yum.repos.d/almalinux*.repo
- name: Update DNF package index - name: Update DNF package index
run: dnf makecache run: dnf makecache
@@ -47,7 +48,7 @@ jobs:
mvn -version mvn -version
- name: Cache Maven packages - name: Cache Maven packages
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: ~/.m2 path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

View File

@@ -17,21 +17,27 @@ jobs:
java-version: [21] # Define the JDK versions to test java-version: [21] # Define the JDK versions to test
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.java-version }} - name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v2 uses: actions/setup-java@v3
with: with:
java-version: ${{ matrix.java-version }} java-version: ${{ matrix.java-version }}
distribution: 'adopt' distribution: 'temurin'
- name: Cache Maven packages - name: Cache Maven packages
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
path: ~/Library/Caches/Maven # macOS Maven cache path path: ~/Library/Caches/Maven # macOS Maven cache path
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2 restore-keys: ${{ runner.os }}-m2
- name: Install system dependencies
run: |
brew update
brew install cmake
brew install gcc
- name: Build with Maven - name: Build with Maven
run: mvn -B package --file pom.xml run: mvn -B package --file pom.xml

View File

@@ -26,7 +26,7 @@ jobs:
distribution: 'adopt' distribution: 'adopt'
- name: Cache Maven packages - name: Cache Maven packages
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: ~/.m2 path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

View File

@@ -26,7 +26,7 @@ jobs:
distribution: 'adopt' # You might need to change this if 'adopt' doesn't support JDK 21 distribution: 'adopt' # You might need to change this if 'adopt' doesn't support JDK 21
- name: Cache Maven packages - name: Cache Maven packages
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: ~\.m2 # Windows uses a backslash for paths path: ~\.m2 # Windows uses a backslash for paths
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

3
.gitignore vendored
View File

@@ -20,4 +20,5 @@ chm_db/
__pycache__/ __pycache__/
/dict /dict
assembly/build/*-SNAPSHOT assembly/build/*-SNAPSHOT
**/node_modules/ **/node_modules/
benchmark/res/

View File

@@ -14,7 +14,7 @@ code and logo.
b. a commercial license must be obtained from the author if you want to develop and distribute a derivative work based b. a commercial license must be obtained from the author if you want to develop and distribute a derivative work based
on SuperSonic. on SuperSonic.
Please contact zhangjun2915@163.com by email to inquire about licensing matters. Please contact supersonicbi@qq.com by email to inquire about licensing matters.
2. As a contributor, you should agree that: 2. As a contributor, you should agree that:

View File

@@ -75,7 +75,7 @@ SuperSonic comes with sample semantic models as well as chat conversations that
## Build and Development ## Build and Development
Please refer to project [Docs](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA/). Please refer to project [Docs](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/).
## WeChat Contact ## WeChat Contact

View File

@@ -75,7 +75,7 @@ SuperSonic自带样例的语义模型和问答对话只需以下三步即可
## 如何构建和部署 ## 如何构建和部署
请参考项目[文档](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA/)。 请参考项目[文档](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/)。
## 微信联系方式 ## 微信联系方式

View File

@@ -71,7 +71,7 @@ SuperSonicには、サンプルのセマンティックモデルとチャット
## ビルドと開発 ## ビルドと開発
プロジェクト[ドキュメント](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA/)を参照してください。 プロジェクト[ドキュメント](https://supersonicbi.github.io/docs/%E7%B3%BB%E7%BB%9F%E9%83%A8%E7%BD%B2/%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E9%83%A8%E7%BD%B2/)を参照してください。
## WeChat連絡先 ## WeChat連絡先

View File

@@ -56,7 +56,7 @@ if "%command%"=="restart" (
set "logDir=%baseDir%\logs" set "logDir=%baseDir%\logs"
set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%" set "classpath=%baseDir%;%webDir%;%libDir%\*;%confDir%"
set "property=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile%" set "property=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile%"
set "java-command=%property% -Xms1024m -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%" set "java-command=%property% -Xms1024m -Xmx2048m -cp %CLASSPATH% %MAIN_CLASS%"
if not exist %logDir% mkdir %logDir% if not exist %logDir% mkdir %logDir%
start /B java %java-command% >nul 2>&1 start /B java %java-command% >nul 2>&1
timeout /t 10 >nul timeout /t 10 >nul

View File

@@ -60,7 +60,8 @@ function runJavaService {
JAVA_HOME=$(ls /usr/jdk64/jdk* -d 2>/dev/null | xargs | awk '{print "'$local_app_name'"}') JAVA_HOME=$(ls /usr/jdk64/jdk* -d 2>/dev/null | xargs | awk '{print "'$local_app_name'"}')
fi fi
export PATH=$JAVA_HOME/bin:$PATH export PATH=$JAVA_HOME/bin:$PATH
command="-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dapp_name=${local_app_name} -Xms1024m -Xmx1024m $main_class" command="-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08
-Dapp_name=${local_app_name} -Xms1024m -Xmx2048m $main_class"
mkdir -p $javaRunDir/logs mkdir -p $javaRunDir/logs
java -Dspring.profiles.active="$profile" $command >/dev/null 2>$javaRunDir/logs/error.log & java -Dspring.profiles.active="$profile" $command >/dev/null 2>$javaRunDir/logs/error.log &

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env sh
export SUPERSONIC_VERSION=latest
docker-compose -f docker-compose.yml -p supersonic up

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env sh
export SUPERSONIC_VERSION=latest
#### Set below DB configs to connect to your own database
# Supported DB_TYPE: h2, mysql, postgres
export S2_DB_TYPE=h2
export S2_DB_HOST=
export S2_DB_PORT=
export S2_DB_USER=
export S2_DB_PASSWORD=
export S2_DB_DATABASE=
docker run --rm -it -d \
--name supersonic_standalone \
-p 9080:9080 \
-e S2_DB_TYPE=${S2_DB_TYPE} \
-e S2_DB_HOST=${S2_DB_HOST} \
-e S2_DB_PORT=${S2_DB_PORT} \
-e S2_DB_USER=${S2_DB_USER} \
-e S2_DB_PASSWORD=${S2_DB_PASSWORD} \
-e S2_DB_DATABASE=${S2_DB_DATABASE} \
supersonicbi/supersonic:${SUPERSONIC_VERSION}

View File

@@ -1,10 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#### Set below DB configs to connect to your own database #### Set below DB configs to connect to your own database
# Comment out below exports to config your DB connection
# Supported DB_TYPE: h2, mysql, postgres # Supported DB_TYPE: h2, mysql, postgres
export S2_DB_TYPE=h2 #export S2_DB_TYPE=h2
export S2_DB_HOST= #export S2_DB_HOST=
export S2_DB_PORT= #export S2_DB_PORT=
export S2_DB_USER= #export S2_DB_USER=
export S2_DB_PASSWORD= #export S2_DB_PASSWORD=
export S2_DB_DATABASE= #export S2_DB_DATABASE=

View File

@@ -34,8 +34,8 @@
</dependencies> </dependencies>
<properties> <properties>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
</properties> </properties>
</project> </project>

View File

@@ -24,7 +24,7 @@ public class UserWithPassword extends User {
public UserWithPassword(Long id, String name, String displayName, String email, String password, public UserWithPassword(Long id, String name, String displayName, String email, String password,
Integer isAdmin) { Integer isAdmin) {
super(id, name, displayName, email, isAdmin); super(id, name, displayName, email, isAdmin, null);
this.password = password; this.password = password;
} }

View File

@@ -18,6 +18,7 @@ import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import java.sql.Timestamp;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@@ -102,7 +103,9 @@ public class DefaultUserAdaptor implements UserAdaptor {
TokenService tokenService = ContextUtils.getBean(TokenService.class); TokenService tokenService = ContextUtils.getBean(TokenService.class);
try { try {
UserWithPassword user = getUserWithPassword(userReq); UserWithPassword user = getUserWithPassword(userReq);
return tokenService.generateToken(UserWithPassword.convert(user), appKey); String token = tokenService.generateToken(UserWithPassword.convert(user), appKey);
updateLastLogin(userReq.getName());
return token;
} catch (Exception e) { } catch (Exception e) {
log.error("", e); log.error("", e);
throw new RuntimeException("password encrypt error, please try again"); throw new RuntimeException("password encrypt error, please try again");
@@ -267,4 +270,11 @@ public class DefaultUserAdaptor implements UserAdaptor {
userToken.setExpireDate(userTokenDO.getExpireDateTime()); userToken.setExpireDate(userTokenDO.getExpireDateTime());
return userToken; return userToken;
} }
private void updateLastLogin(String userName) {
UserRepository userRepository = ContextUtils.getBean(UserRepository.class);
UserDO userDO = userRepository.getUser(userName);
userDO.setLastLogin(new Timestamp(System.currentTimeMillis()));
userRepository.updateUser(userDO);
}
} }

View File

@@ -1,7 +1,7 @@
package com.tencent.supersonic.auth.authentication.interceptor; package com.tencent.supersonic.auth.authentication.interceptor;
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl; import com.tencent.supersonic.auth.api.authentication.service.UserService;
import com.tencent.supersonic.auth.authentication.utils.TokenService; import com.tencent.supersonic.auth.authentication.utils.TokenService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -16,7 +16,7 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
protected AuthenticationConfig authenticationConfig; protected AuthenticationConfig authenticationConfig;
protected UserServiceImpl userServiceImpl; protected UserService userService;
protected TokenService tokenService; protected TokenService tokenService;

View File

@@ -3,7 +3,7 @@ package com.tencent.supersonic.auth.authentication.interceptor;
import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore; import com.tencent.supersonic.auth.api.authentication.annotation.AuthenticationIgnore;
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig; import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword; import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl; import com.tencent.supersonic.auth.api.authentication.service.UserService;
import com.tencent.supersonic.auth.authentication.utils.TokenService; import com.tencent.supersonic.auth.authentication.utils.TokenService;
import com.tencent.supersonic.common.pojo.exception.AccessException; import com.tencent.supersonic.common.pojo.exception.AccessException;
import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.ContextUtils;
@@ -16,12 +16,7 @@ import org.springframework.web.method.HandlerMethod;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Optional; import java.util.Optional;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_IS_ADMIN; import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.*;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_DISPLAY_NAME;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_EMAIL;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_ID;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_NAME;
import static com.tencent.supersonic.auth.api.authentication.constant.UserConstants.TOKEN_USER_PASSWORD;
@Slf4j @Slf4j
public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor { public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor {
@@ -30,7 +25,7 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws AccessException { Object handler) throws AccessException {
authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class); authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class);
userServiceImpl = ContextUtils.getBean(UserServiceImpl.class); userService = ContextUtils.getBean(UserService.class);
tokenService = ContextUtils.getBean(TokenService.class); tokenService = ContextUtils.getBean(TokenService.class);
if (!authenticationConfig.isEnabled()) { if (!authenticationConfig.isEnabled()) {
return true; return true;

View File

@@ -3,7 +3,11 @@ package com.tencent.supersonic.auth.authentication.persistence.dataobject;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.sql.Timestamp;
@Data
@TableName("s2_user") @TableName("s2_user")
public class UserDO { public class UserDO {
@@ -27,71 +31,25 @@ public class UserDO {
/** */ /** */
private Integer isAdmin; private Integer isAdmin;
/** @return id */ private Timestamp lastLogin;
public Long getId() {
return id;
}
/** @param id */
public void setId(Long id) {
this.id = id;
}
/** @return name */
public String getName() {
return name;
}
/** @param name */ /** @param name */
public void setName(String name) { public void setName(String name) {
this.name = name == null ? null : name.trim(); this.name = name == null ? null : name.trim();
} }
/** @return password */
public String getPassword() {
return password;
}
/** @param password */ /** @param password */
public void setPassword(String password) { public void setPassword(String password) {
this.password = password == null ? null : password.trim(); this.password = password == null ? null : password.trim();
} }
public String getSalt() {
return salt;
}
public void setSalt(String salt) { public void setSalt(String salt) {
this.salt = salt == null ? null : salt.trim(); this.salt = salt == null ? null : salt.trim();
} }
/** @return display_name */
public String getDisplayName() {
return displayName;
}
/** @param displayName */
public void setDisplayName(String displayName) {
this.displayName = displayName == null ? null : displayName.trim();
}
/** @return email */
public String getEmail() {
return email;
}
/** @param email */ /** @param email */
public void setEmail(String email) { public void setEmail(String email) {
this.email = email == null ? null : email.trim(); this.email = email == null ? null : email.trim();
} }
/** @return is_admin */
public Integer getIsAdmin() {
return isAdmin;
}
/** @param isAdmin */
public void setIsAdmin(Integer isAdmin) {
this.isAdmin = isAdmin;
}
} }

View File

@@ -9,6 +9,7 @@
<result column="display_name" jdbcType="VARCHAR" property="displayName" /> <result column="display_name" jdbcType="VARCHAR" property="displayName" />
<result column="email" jdbcType="VARCHAR" property="email" /> <result column="email" jdbcType="VARCHAR" property="email" />
<result column="is_admin" jdbcType="INTEGER" property="isAdmin" /> <result column="is_admin" jdbcType="INTEGER" property="isAdmin" />
<result column="last_login" jdbcType="TIMESTAMP" property="lastLogin" />
</resultMap> </resultMap>
<sql id="Example_Where_Clause"> <sql id="Example_Where_Clause">
<where> <where>
@@ -40,7 +41,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, name, password, salt, display_name, email, is_admin id, name, password, salt, display_name, email, is_admin, last_login
</sql> </sql>
<select id="selectByExample" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample" resultMap="BaseResultMap">
select select
@@ -136,6 +137,9 @@
<if test="isAdmin != null"> <if test="isAdmin != null">
is_admin = #{isAdmin,jdbcType=INTEGER}, is_admin = #{isAdmin,jdbcType=INTEGER},
</if> </if>
<if test="lastLogin != null">
last_login = #{lastLogin,jdbcType=TIMESTAMP},
</if>
</set> </set>
where id = #{id,jdbcType=BIGINT} where id = #{id,jdbcType=BIGINT}
</update> </update>

View File

@@ -15,6 +15,68 @@ import requests
import time import time
import jwt import jwt
import traceback import traceback
import os
from datetime import datetime
class DataFrameAppender:
def __init__(self,file_name = "output"):
# 定义表头
columns = ['问题', '解析状态', '解析耗时', '执行状态', '执行耗时', '总耗时']
# 创建只有表头的 DataFrame
self.df = pd.DataFrame(columns=columns)
self.file_name = file_name
def append_data(self, new_data):
# 假设 new_data 是一维数组,将其转换为字典
columns = ['问题', '解析状态', '解析耗时', '执行状态', '执行耗时', '总耗时']
new_dict = dict(zip(columns, new_data))
# 使用 loc 方法追加数据
self.df.loc[len(self.df)] = new_dict
def print_analysis_result(self):
# 测试样例总数
total_samples = len(self.df)
# 解析成功数量
parse_success_count = (self.df['解析状态'] == '解析成功').sum()
# 执行成功数量
execute_success_count = (self.df['执行状态'] == '执行成功').sum()
# 解析平均耗时,保留两位小数
avg_parse_time = round(self.df['解析耗时'].mean(), 2)
# 执行平均耗时,保留两位小数
avg_execute_time = round(self.df['执行耗时'].mean(), 2)
# 总平均耗时,保留两位小数
avg_total_time = round(self.df['总耗时'].mean(), 2)
# 最长耗时,保留两位小数
max_time = round(self.df['总耗时'].max(), 2)
# 最短耗时,保留两位小数
min_time = round(self.df['总耗时'].min(), 2)
print(f"测试样例总数 : {total_samples}")
print(f"解析成功数量 : {parse_success_count}")
print(f"执行成功数量 : {execute_success_count}")
print(f"解析平均耗时 : {avg_parse_time}")
print(f"执行平均耗时 : {avg_execute_time}")
print(f"总平均耗时 : {avg_total_time}")
print(f"最长耗时 : {max_time}")
print(f"最短耗时 : {min_time}")
def write_to_csv(self):
# 检查 data 文件夹是否存在,如果不存在则创建
if not os.path.exists('res'):
os.makedirs('res')
# 获取当前时间戳
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
# 生成带时间戳的文件名
file_path = os.path.join('res', f'{self.file_name}_{timestamp}.csv')
self.df.to_csv(file_path, index=False)
print(f"测试结果已保存到 {file_path}")
class BatchTest: class BatchTest:
def __init__(self, url, agentId, chatId, userName): def __init__(self, url, agentId, chatId, userName):
@@ -70,18 +132,35 @@ class BatchTest:
def benchmark(url:str, agentId:str, chatId:str, filePath:str, userName:str): def benchmark(url:str, agentId:str, chatId:str, filePath:str, userName:str):
batch_test = BatchTest(url, agentId, chatId, userName) batch_test = BatchTest(url, agentId, chatId, userName)
df = batch_test.read_question_from_csv(filePath) df = batch_test.read_question_from_csv(filePath)
appender = DataFrameAppender(os.path.basename(filePath))
for index, row in df.iterrows(): for index, row in df.iterrows():
question = row['question'] question = row['question']
print('start to ask question:', question) print('start to ask question:', question)
# 捕获异常,防止程序中断 # 捕获异常,防止程序中断
try: try:
parse_resp = batch_test.parse(question) parse_resp = batch_test.parse(question)
batch_test.execute(agentId, question, parse_resp['data']['queryId']) parse_status = '解析失败'
if parse_resp.get('data').get('errorMsg') is None:
parse_status = '解析成功'
parse_cost = parse_resp.get('data').get('parseTimeCost').get('parseTime')
execute_resp = batch_test.execute(agentId, question, parse_resp['data']['queryId'])
execute_status = '执行失败'
execute_cost = 0
if parse_status == '解析成功' and execute_resp.get('data').get('errorMsg') is None:
execute_status = '执行成功'
execute_cost = execute_resp.get('data').get('queryTimeCost')
res = [question.replace(',', '#'),parse_status,parse_cost/1000,execute_status,execute_cost/1000,(parse_cost+execute_cost)/1000]
appender.append_data(res)
except Exception as e: except Exception as e:
print('error:', e) print('error:', e)
traceback.print_exc() traceback.print_exc()
continue continue
time.sleep(1) time.sleep(1)
# 打印分析结果
appender.print_analysis_result()
# 分析明细输出
appender.write_to_csv()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -5,5 +5,7 @@ import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
public interface ChatQueryExecutor { public interface ChatQueryExecutor {
boolean accept(ExecuteContext executeContext);
QueryResult execute(ExecuteContext executeContext); QueryResult execute(ExecuteContext executeContext);
} }

View File

@@ -37,11 +37,12 @@ public class PlainTextExecutor implements ChatQueryExecutor {
} }
@Override @Override
public QueryResult execute(ExecuteContext executeContext) { public boolean accept(ExecuteContext executeContext) {
if (!"PLAIN_TEXT".equals(executeContext.getParseInfo().getQueryMode())) { return "PLAIN_TEXT".equals(executeContext.getParseInfo().getQueryMode());
return null; }
}
@Override
public QueryResult execute(ExecuteContext executeContext) {
AgentService agentService = ContextUtils.getBean(AgentService.class); AgentService agentService = ContextUtils.getBean(AgentService.class);
Agent chatAgent = agentService.getAgent(executeContext.getAgent().getId()); Agent chatAgent = agentService.getAgent(executeContext.getAgent().getId());
ChatApp chatApp = chatAgent.getChatAppConfig().get(APP_KEY); ChatApp chatApp = chatAgent.getChatAppConfig().get(APP_KEY);

View File

@@ -8,6 +8,11 @@ import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
public class PluginExecutor implements ChatQueryExecutor { public class PluginExecutor implements ChatQueryExecutor {
@Override
public boolean accept(ExecuteContext executeContext) {
return PluginQueryManager.isPluginQuery(executeContext.getParseInfo().getQueryMode());
}
@Override @Override
public QueryResult execute(ExecuteContext executeContext) { public QueryResult execute(ExecuteContext executeContext) {
SemanticParseInfo parseInfo = executeContext.getParseInfo(); SemanticParseInfo parseInfo = executeContext.getParseInfo();

View File

@@ -25,6 +25,11 @@ import java.util.Objects;
public class SqlExecutor implements ChatQueryExecutor { public class SqlExecutor implements ChatQueryExecutor {
@Override
public boolean accept(ExecuteContext executeContext) {
return true;
}
@SneakyThrows @SneakyThrows
@Override @Override
public QueryResult execute(ExecuteContext executeContext) { public QueryResult execute(ExecuteContext executeContext) {
@@ -80,9 +85,9 @@ public class SqlExecutor implements ChatQueryExecutor {
queryResult.setQueryId(executeContext.getRequest().getQueryId()); queryResult.setQueryId(executeContext.getRequest().getQueryId());
queryResult.setChatContext(parseInfo); queryResult.setChatContext(parseInfo);
queryResult.setQueryMode(parseInfo.getQueryMode()); queryResult.setQueryMode(parseInfo.getQueryMode());
queryResult.setQueryTimeCost(System.currentTimeMillis() - startTime);
SemanticQueryResp queryResp = SemanticQueryResp queryResp =
semanticLayer.queryByReq(sqlReq, executeContext.getRequest().getUser()); semanticLayer.queryByReq(sqlReq, executeContext.getRequest().getUser());
queryResult.setQueryTimeCost(System.currentTimeMillis() - startTime);
if (queryResp != null) { if (queryResp != null) {
queryResult.setQueryAuthorization(queryResp.getQueryAuthorization()); queryResult.setQueryAuthorization(queryResp.getQueryAuthorization());
queryResult.setQuerySql(queryResp.getSql()); queryResult.setQuerySql(queryResp.getSql());

View File

@@ -4,5 +4,7 @@ import com.tencent.supersonic.chat.server.pojo.ParseContext;
public interface ChatQueryParser { public interface ChatQueryParser {
boolean accept(ParseContext parseContext);
void parse(ParseContext parseContext); void parse(ParseContext parseContext);
} }

View File

@@ -14,12 +14,12 @@ public class NL2PluginParser implements ChatQueryParser {
private final List<PluginRecognizer> pluginRecognizers = private final List<PluginRecognizer> pluginRecognizers =
ComponentFactory.getPluginRecognizers(); ComponentFactory.getPluginRecognizers();
public boolean accept(ParseContext parseContext) {
return parseContext.getAgent().containsPluginTool();
}
@Override @Override
public void parse(ParseContext parseContext) { public void parse(ParseContext parseContext) {
if (!parseContext.getAgent().containsPluginTool()) {
return;
}
pluginRecognizers.forEach(pluginRecognizer -> { pluginRecognizers.forEach(pluginRecognizer -> {
pluginRecognizer.recognize(parseContext); pluginRecognizer.recognize(parseContext);
log.info("{} recallResult:{}", pluginRecognizer.getClass().getSimpleName(), log.info("{} recallResult:{}", pluginRecognizer.getClass().getSimpleName(),

View File

@@ -73,12 +73,12 @@ public class NL2SQLParser implements ChatQueryParser {
.build()); .build());
} }
public boolean accept(ParseContext parseContext) {
return parseContext.enableNL2SQL();
}
@Override @Override
public void parse(ParseContext parseContext) { public void parse(ParseContext parseContext) {
if (!parseContext.enableNL2SQL()) {
return;
}
// first go with rule-based parsers unless the user has already selected one parse. // first go with rule-based parsers unless the user has already selected one parse.
if (Objects.isNull(parseContext.getRequest().getSelectedParse())) { if (Objects.isNull(parseContext.getRequest().getSelectedParse())) {
QueryNLReq queryNLReq = QueryReqConverter.buildQueryNLReq(parseContext); QueryNLReq queryNLReq = QueryReqConverter.buildQueryNLReq(parseContext);

View File

@@ -6,12 +6,12 @@ import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
public class PlainTextParser implements ChatQueryParser { public class PlainTextParser implements ChatQueryParser {
public boolean accept(ParseContext parseContext) {
return !parseContext.getAgent().containsAnyTool();
}
@Override @Override
public void parse(ParseContext parseContext) { public void parse(ParseContext parseContext) {
if (parseContext.getAgent().containsAnyTool()) {
return;
}
SemanticParseInfo parseInfo = new SemanticParseInfo(); SemanticParseInfo parseInfo = new SemanticParseInfo();
parseInfo.setQueryMode("PLAIN_TEXT"); parseInfo.setQueryMode("PLAIN_TEXT");
parseInfo.setId(1); parseInfo.setId(1);

View File

@@ -66,8 +66,10 @@ public class ChatConfigController {
} }
@GetMapping("/getDomainDataSetTree") @GetMapping("/getDomainDataSetTree")
public List<ItemResp> getDomainDataSetTree() { public List<ItemResp> getDomainDataSetTree(HttpServletRequest request,
return semanticLayerService.getDomainDataSetTree(); HttpServletResponse response) {
User user = UserHolder.findUser(request, response);
return semanticLayerService.getDomainDataSetTree(user);
} }
@GetMapping("/getDataSetSchema/{id}") @GetMapping("/getDataSetSchema/{id}")

View File

@@ -22,11 +22,10 @@ public class ChatController {
private ChatManageService chatService; private ChatManageService chatService;
@PostMapping("/save") @PostMapping("/save")
public Boolean save(@RequestParam(value = "chatName") String chatName, public Long save(@RequestParam(value = "chatName") String chatName,
@RequestParam(value = "agentId", required = false) Integer agentId, @RequestParam(value = "agentId", required = false) Integer agentId,
HttpServletRequest request, HttpServletResponse response) { HttpServletRequest request, HttpServletResponse response) {
chatService.addChat(UserHolder.findUser(request, response), chatName, agentId); return chatService.addChat(UserHolder.findUser(request, response), chatName, agentId);
return true;
} }
@GetMapping("/getAll") @GetMapping("/getAll")

View File

@@ -161,9 +161,11 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
JsonUtil.toMap(agentDO.getChatModelConfig(), String.class, ChatApp.class)); JsonUtil.toMap(agentDO.getChatModelConfig(), String.class, ChatApp.class));
agent.setVisualConfig(JsonUtil.toObject(agentDO.getVisualConfig(), VisualConfig.class)); agent.setVisualConfig(JsonUtil.toObject(agentDO.getVisualConfig(), VisualConfig.class));
agent.getChatAppConfig().values().forEach(c -> { agent.getChatAppConfig().values().forEach(c -> {
ChatModel chatModel = chatModelService.getChatModel(c.getChatModelId()); if (c.isEnable()) {// 优化,减少访问数据库的次数
if (Objects.nonNull(chatModel)) { ChatModel chatModel = chatModelService.getChatModel(c.getChatModelId());
c.setChatModelConfig(chatModelService.getChatModel(c.getChatModelId()).getConfig()); if (Objects.nonNull(chatModel)) {
c.setChatModelConfig(chatModel.getConfig());
}
} }
}); });
agent.setAdmins(JsonUtil.toList(agentDO.getAdmin(), String.class)); agent.setAdmins(JsonUtil.toList(agentDO.getAdmin(), String.class));

View File

@@ -233,6 +233,10 @@ public class ChatManageServiceImpl implements ChatManageService {
@Override @Override
public SemanticParseInfo getParseInfo(Long questionId, int parseId) { public SemanticParseInfo getParseInfo(Long questionId, int parseId) {
ChatParseDO chatParseDO = chatQueryRepository.getParseInfo(questionId, parseId); ChatParseDO chatParseDO = chatQueryRepository.getParseInfo(questionId, parseId);
return JSONObject.parseObject(chatParseDO.getParseInfo(), SemanticParseInfo.class); if (chatParseDO == null) {
return null;
} else {
return JSONObject.parseObject(chatParseDO.getParseInfo(), SemanticParseInfo.class);
}
} }
} }

View File

@@ -95,7 +95,11 @@ public class ChatQueryServiceImpl implements ChatQueryService {
} }
ParseContext parseContext = buildParseContext(chatParseReq, new ChatParseResp(queryId)); ParseContext parseContext = buildParseContext(chatParseReq, new ChatParseResp(queryId));
chatQueryParsers.forEach(p -> p.parse(parseContext)); for (ChatQueryParser parser : chatQueryParsers) {
if (parser.accept(parseContext)) {
parser.parse(parseContext);
}
}
for (ParseResultProcessor processor : parseResultProcessors) { for (ParseResultProcessor processor : parseResultProcessors) {
if (processor.accept(parseContext)) { if (processor.accept(parseContext)) {
@@ -116,9 +120,11 @@ public class ChatQueryServiceImpl implements ChatQueryService {
QueryResult queryResult = new QueryResult(); QueryResult queryResult = new QueryResult();
ExecuteContext executeContext = buildExecuteContext(chatExecuteReq); ExecuteContext executeContext = buildExecuteContext(chatExecuteReq);
for (ChatQueryExecutor chatQueryExecutor : chatQueryExecutors) { for (ChatQueryExecutor chatQueryExecutor : chatQueryExecutors) {
queryResult = chatQueryExecutor.execute(executeContext); if (chatQueryExecutor.accept(executeContext)) {
if (queryResult != null) { queryResult = chatQueryExecutor.execute(executeContext);
break; if (queryResult != null) {
break;
}
} }
} }

View File

@@ -18,19 +18,23 @@ import com.tencent.supersonic.common.config.EmbeddingConfig;
import com.tencent.supersonic.common.pojo.Text2SQLExemplar; import com.tencent.supersonic.common.pojo.Text2SQLExemplar;
import com.tencent.supersonic.common.pojo.User; import com.tencent.supersonic.common.pojo.User;
import com.tencent.supersonic.common.service.ExemplarService; import com.tencent.supersonic.common.service.ExemplarService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
public class MemoryServiceImpl implements MemoryService { @Slf4j
public class MemoryServiceImpl implements MemoryService, CommandLineRunner {
@Autowired @Autowired
private ChatMemoryRepository chatMemoryRepository; private ChatMemoryRepository chatMemoryRepository;
@@ -87,6 +91,12 @@ public class MemoryServiceImpl implements MemoryService {
updateWrapper.set(ChatMemoryDO::getHumanReviewCmt, updateWrapper.set(ChatMemoryDO::getHumanReviewCmt,
chatMemoryUpdateReq.getHumanReviewCmt()); chatMemoryUpdateReq.getHumanReviewCmt());
} }
if (Objects.nonNull(chatMemoryUpdateReq.getDbSchema())) {
updateWrapper.set(ChatMemoryDO::getDbSchema, chatMemoryUpdateReq.getDbSchema());
}
if (Objects.nonNull(chatMemoryUpdateReq.getS2sql())) {
updateWrapper.set(ChatMemoryDO::getS2sql, chatMemoryUpdateReq.getS2sql());
}
updateWrapper.set(ChatMemoryDO::getUpdatedAt, new Date()); updateWrapper.set(ChatMemoryDO::getUpdatedAt, new Date());
updateWrapper.set(ChatMemoryDO::getUpdatedBy, user.getName()); updateWrapper.set(ChatMemoryDO::getUpdatedBy, user.getName());
@@ -187,4 +197,25 @@ public class MemoryServiceImpl implements MemoryService {
return memory; return memory;
} }
@Override
public void run(String... args) { // 优化,启动时检查,向量数据,将记忆放到向量数据库
loadSysExemplars();
}
public void loadSysExemplars() {
try {
List<ChatMemory> memories = this
.getMemories(ChatMemoryFilter.builder().status(MemoryStatus.ENABLED).build());
for (ChatMemory memory : memories) {
exemplarService.storeExemplar(
embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
Text2SQLExemplar.builder().question(memory.getQuestion())
.sideInfo(memory.getSideInfo()).dbSchema(memory.getDbSchema())
.sql(memory.getS2sql()).build());
}
} catch (Exception e) {
log.error("Failed to load system exemplars", e);
}
}
} }

View File

@@ -77,11 +77,6 @@ public class SemanticSqlConformance implements SqlConformance {
return SqlConformanceEnum.BIG_QUERY.isMinusAllowed(); return SqlConformanceEnum.BIG_QUERY.isMinusAllowed();
} }
@Override
public boolean isRegexReplaceCaptureGroupDollarIndexed() {
return SqlConformanceEnum.BIG_QUERY.isRegexReplaceCaptureGroupDollarIndexed();
}
@Override @Override
public boolean isApplyAllowed() { public boolean isApplyAllowed() {
return SqlConformanceEnum.BIG_QUERY.isApplyAllowed(); return SqlConformanceEnum.BIG_QUERY.isApplyAllowed();

View File

@@ -26,6 +26,16 @@ public class SqlDialectFactory {
.withLiteralQuoteString("'").withIdentifierQuoteString("\"") .withLiteralQuoteString("'").withIdentifierQuoteString("\"")
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED) .withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true); .withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
public static final Context PRESTO_CONTEXT =
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.PRESTO)
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
public static final Context KYUUBI_CONTEXT =
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.BIG_QUERY)
.withLiteralQuoteString("'").withIdentifierQuoteString("`")
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(false);
private static Map<EngineType, SemanticSqlDialect> sqlDialectMap; private static Map<EngineType, SemanticSqlDialect> sqlDialectMap;
static { static {
@@ -35,6 +45,10 @@ public class SqlDialectFactory {
sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT)); sqlDialectMap.put(EngineType.H2, new SemanticSqlDialect(DEFAULT_CONTEXT));
sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_CONTEXT)); sqlDialectMap.put(EngineType.POSTGRESQL, new SemanticSqlDialect(POSTGRESQL_CONTEXT));
sqlDialectMap.put(EngineType.HANADB, new SemanticSqlDialect(HANADB_CONTEXT)); sqlDialectMap.put(EngineType.HANADB, new SemanticSqlDialect(HANADB_CONTEXT));
sqlDialectMap.put(EngineType.STARROCKS, new SemanticSqlDialect(DEFAULT_CONTEXT));
sqlDialectMap.put(EngineType.KYUUBI, new SemanticSqlDialect(KYUUBI_CONTEXT));
sqlDialectMap.put(EngineType.PRESTO, new SemanticSqlDialect(PRESTO_CONTEXT));
sqlDialectMap.put(EngineType.TRINO, new SemanticSqlDialect(PRESTO_CONTEXT));
} }
public static SemanticSqlDialect getSqlDialect(EngineType engineType) { public static SemanticSqlDialect getSqlDialect(EngineType engineType) {

View File

@@ -2,19 +2,11 @@ package com.tencent.supersonic.common.calcite;
import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.common.pojo.enums.EngineType;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.sql.SqlIdentifier; import net.sf.jsqlparser.expression.Alias;
import org.apache.calcite.sql.SqlLiteral; import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.calcite.sql.SqlNode; import net.sf.jsqlparser.statement.select.ParenthesedSelect;
import org.apache.calcite.sql.SqlNodeList; import net.sf.jsqlparser.statement.select.Select;
import org.apache.calcite.sql.SqlOrderBy; import net.sf.jsqlparser.statement.select.WithItem;
import org.apache.calcite.sql.SqlSelect;
import org.apache.calcite.sql.SqlWith;
import org.apache.calcite.sql.SqlWithItem;
import org.apache.calcite.sql.SqlWriterConfig;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.pretty.SqlPrettyWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -22,85 +14,37 @@ import java.util.List;
@Slf4j @Slf4j
public class SqlMergeWithUtils { public class SqlMergeWithUtils {
public static String mergeWith(EngineType engineType, String sql, List<String> parentSqlList, public static String mergeWith(EngineType engineType, String sql, List<String> parentSqlList,
List<String> parentWithNameList) throws SqlParseException { List<String> parentWithNameList) throws Exception {
SqlParser.Config parserConfig = Configuration.getParserConfig(engineType);
// Parse the main SQL statement Select selectStatement = (Select) CCJSqlParserUtil.parse(sql);
SqlParser parser = SqlParser.create(sql, parserConfig); List<WithItem> withItemList = new ArrayList<>();
SqlNode sqlNode1 = parser.parseQuery();
// List to hold all WITH items
List<SqlNode> withItemList = new ArrayList<>();
// Iterate over each parentSql and parentWithName pair
for (int i = 0; i < parentSqlList.size(); i++) { for (int i = 0; i < parentSqlList.size(); i++) {
String parentSql = parentSqlList.get(i); String parentSql = parentSqlList.get(i);
String parentWithName = parentWithNameList.get(i); String parentWithName = parentWithNameList.get(i);
// Parse the parent SQL statement Select parentSelect = (Select) CCJSqlParserUtil.parse(parentSql);
parser = SqlParser.create(parentSql, parserConfig); ParenthesedSelect select = new ParenthesedSelect();
SqlNode sqlNode2 = parser.parseQuery(); select.setSelect(parentSelect);
// Create a new WITH item for parentWithName without quotes // Create a new WITH item for parentWithName without quotes
SqlWithItem withItem = new SqlWithItem(SqlParserPos.ZERO, WithItem withItem = new WithItem();
new SqlIdentifier(parentWithName, SqlParserPos.ZERO), null, sqlNode2, withItem.setAlias(new Alias(parentWithName));
SqlLiteral.createBoolean(false, SqlParserPos.ZERO)); withItem.setSelect(select);
// Add the new WITH item to the list // Add the new WITH item to the list
withItemList.add(withItem); withItemList.add(withItem);
} }
// Check if the main SQL node contains an ORDER BY or LIMIT clause // Extract existing WITH items from mainSelectBody if it has any
SqlNode limitNode = null; if (selectStatement.getWithItemsList() != null) {
SqlNodeList orderByList = null; withItemList.addAll(selectStatement.getWithItemsList());
if (sqlNode1 instanceof SqlOrderBy) {
SqlOrderBy sqlOrderBy = (SqlOrderBy) sqlNode1;
limitNode = sqlOrderBy.fetch;
orderByList = sqlOrderBy.orderList;
sqlNode1 = sqlOrderBy.query;
} else if (sqlNode1 instanceof SqlSelect) {
SqlSelect sqlSelect = (SqlSelect) sqlNode1;
limitNode = sqlSelect.getFetch();
sqlSelect.setFetch(null);
sqlNode1 = sqlSelect;
} }
// Extract existing WITH items from sqlNode1 if it is a SqlWith // Set the new WITH items list to the main select body
if (sqlNode1 instanceof SqlWith) { selectStatement.setWithItemsList(withItemList);
SqlWith sqlWith = (SqlWith) sqlNode1;
withItemList.addAll(sqlWith.withList.getList());
sqlNode1 = sqlWith.body;
}
// Create a new SqlWith node
SqlWith finalSqlNode = new SqlWith(SqlParserPos.ZERO,
new SqlNodeList(withItemList, SqlParserPos.ZERO), sqlNode1);
// If there was an ORDER BY or LIMIT clause, wrap the finalSqlNode in a SqlOrderBy
SqlNode resultNode = finalSqlNode;
if (orderByList != null || limitNode != null) {
resultNode = new SqlOrderBy(SqlParserPos.ZERO, finalSqlNode,
orderByList != null ? orderByList : SqlNodeList.EMPTY, null, limitNode);
}
// Custom SqlPrettyWriter configuration to avoid quoting identifiers
SqlWriterConfig config = Configuration.getSqlWriterConfig(engineType);
// Pretty print the final SQL // Pretty print the final SQL
SqlPrettyWriter writer = new SqlPrettyWriter(config); return selectStatement.toString();
return writer.format(resultNode);
}
public static boolean hasWith(EngineType engineType, String sql) throws SqlParseException {
SqlParser.Config parserConfig = Configuration.getParserConfig(engineType);
SqlParser parser = SqlParser.create(sql, parserConfig);
SqlNode sqlNode = parser.parseQuery();
SqlNode sqlSelect = sqlNode;
if (sqlNode instanceof SqlOrderBy) {
SqlOrderBy sqlOrderBy = (SqlOrderBy) sqlNode;
sqlSelect = sqlOrderBy.query;
} else if (sqlNode instanceof SqlSelect) {
sqlSelect = (SqlSelect) sqlNode;
}
return sqlSelect instanceof SqlWith;
} }
} }

View File

@@ -1,9 +1,11 @@
package com.tencent.supersonic.common.config; package com.tencent.supersonic.common.config;
import com.google.common.collect.Lists;
import com.tencent.supersonic.common.pojo.ChatModelConfig; import com.tencent.supersonic.common.pojo.ChatModelConfig;
import lombok.Data; import lombok.Data;
import java.util.Date; import java.util.Date;
import java.util.List;
@Data @Data
public class ChatModel { public class ChatModel {
@@ -25,5 +27,11 @@ public class ChatModel {
private String admin; private String admin;
private String viewer; private List<String> viewers = Lists.newArrayList();
private Integer isOpen = 0;
public boolean isPublic() {
return isOpen != null && isOpen == 1;
}
} }

View File

@@ -91,7 +91,8 @@ public class FiledFilterReplaceVisitor extends ExpressionVisitorAdapter {
} }
ExpressionList<?> leftFunctionParams = leftFunction.getParameters(); ExpressionList<?> leftFunctionParams = leftFunction.getParameters();
if (CollectionUtils.isEmpty(leftFunctionParams)) { if (CollectionUtils.isEmpty(leftFunctionParams)
|| !(leftFunctionParams.get(0) instanceof Column)) {
return result; return result;
} }

View File

@@ -146,6 +146,10 @@ public class SqlReplaceHelper {
public static String replaceFields(String sql, Map<String, String> fieldNameMap, public static String replaceFields(String sql, Map<String, String> fieldNameMap,
boolean exactReplace) { boolean exactReplace) {
Select selectStatement = SqlSelectHelper.getSelect(sql); Select selectStatement = SqlSelectHelper.getSelect(sql);
// alias field should not be replaced
Set<String> aliases = SqlSelectHelper.getAliasFields(sql);
aliases.forEach(alias -> fieldNameMap.put(alias, alias));
Set<Select> plainSelectList = SqlSelectHelper.getAllSelect(selectStatement); Set<Select> plainSelectList = SqlSelectHelper.getAllSelect(selectStatement);
for (Select plainSelect : plainSelectList) { for (Select plainSelect : plainSelectList) {
if (plainSelect instanceof PlainSelect) { if (plainSelect instanceof PlainSelect) {

View File

@@ -989,6 +989,15 @@ public class SqlSelectHelper {
for (SelectItem selectItem : selectItems) { for (SelectItem selectItem : selectItems) {
selectItem.accept(visitor); selectItem.accept(visitor);
} }
if (plainSelect.getHaving() != null) {
plainSelect.getHaving().accept(visitor);
}
if (!CollectionUtils.isEmpty(plainSelect.getOrderByElements())) {
for (OrderByElement orderByElement : plainSelect.getOrderByElements()) {
orderByElement.getExpression().accept(visitor);
}
}
return !visitor.getFunctionNames().isEmpty(); return !visitor.getFunctionNames().isEmpty();
} }

View File

@@ -30,4 +30,6 @@ public class ChatModelDO {
private String admin; private String admin;
private String viewer; private String viewer;
private Integer isOpen;
} }

View File

@@ -3,6 +3,7 @@ package com.tencent.supersonic.common.pojo;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER; import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER;

View File

@@ -6,6 +6,7 @@ import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Timestamp;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@@ -22,26 +23,28 @@ public class User implements Serializable {
private Integer isAdmin; private Integer isAdmin;
private Timestamp lastLogin;
public static User get(Long id, String name, String displayName, String email, public static User get(Long id, String name, String displayName, String email,
Integer isAdmin) { Integer isAdmin) {
return new User(id, name, displayName, email, isAdmin); return new User(id, name, displayName, email, isAdmin, null);
} }
public static User get(Long id, String name) { public static User get(Long id, String name) {
return new User(id, name, name, name, 0); return new User(id, name, name, name, 0, null);
} }
public static User getDefaultUser() { public static User getDefaultUser() {
return new User(1L, "admin", "admin", "admin@email", 1); return new User(1L, "admin", "admin", "admin@email", 1, null);
} }
public static User getVisitUser() { public static User getVisitUser() {
return new User(1L, "visit", "visit", "visit@email", 0); return new User(1L, "visit", "visit", "visit@email", 0, null);
} }
public static User getAppUser(int appId) { public static User getAppUser(int appId) {
String name = String.format("app_%s", appId); String name = String.format("app_%s", appId);
return new User(1L, name, name, "", 1); return new User(1L, name, name, "", 1, null);
} }
public String getDisplayName() { public String getDisplayName() {

View File

@@ -7,7 +7,7 @@ import com.tencent.supersonic.common.pojo.User;
import java.util.List; import java.util.List;
public interface ChatModelService { public interface ChatModelService {
List<ChatModel> getChatModels(); List<ChatModel> getChatModels(User user);
ChatModel getChatModel(Integer id); ChatModel getChatModel(Integer id);

View File

@@ -23,8 +23,15 @@ import java.util.stream.Collectors;
public class ChatModelServiceImpl extends ServiceImpl<ChatModelMapper, ChatModelDO> public class ChatModelServiceImpl extends ServiceImpl<ChatModelMapper, ChatModelDO>
implements ChatModelService { implements ChatModelService {
@Override @Override
public List<ChatModel> getChatModels() { public List<ChatModel> getChatModels(User user) {
return list().stream().map(this::convert).collect(Collectors.toList()); return list().stream().map(this::convert).filter(chatModel -> {
if (chatModel.isPublic() || user.isSuperAdmin()
|| chatModel.getCreatedBy().equals(user.getName())
|| chatModel.getViewers().contains(user.getName())) {
return true;
}
return false;
}).collect(Collectors.toList());
} }
@Override @Override
@@ -41,10 +48,14 @@ public class ChatModelServiceImpl extends ServiceImpl<ChatModelMapper, ChatModel
chatModelDO.setCreatedBy(user.getName()); chatModelDO.setCreatedBy(user.getName());
chatModelDO.setCreatedAt(new Date()); chatModelDO.setCreatedAt(new Date());
chatModelDO.setUpdatedBy(user.getName()); chatModelDO.setUpdatedBy(user.getName());
chatModelDO.setUpdatedAt(new Date()); chatModelDO.setUpdatedAt(chatModelDO.getCreatedAt());
chatModelDO.setIsOpen(chatModel.getIsOpen());
if (StringUtils.isBlank(chatModel.getAdmin())) { if (StringUtils.isBlank(chatModel.getAdmin())) {
chatModelDO.setAdmin(user.getName()); chatModelDO.setAdmin(user.getName());
} }
if (!chatModel.getViewers().isEmpty()) {
chatModelDO.setViewer(JsonUtil.toString(chatModel.getViewers()));
}
save(chatModelDO); save(chatModelDO);
chatModel.setId(chatModelDO.getId()); chatModel.setId(chatModelDO.getId());
return chatModel; return chatModel;
@@ -55,9 +66,13 @@ public class ChatModelServiceImpl extends ServiceImpl<ChatModelMapper, ChatModel
ChatModelDO chatModelDO = convert(chatModel); ChatModelDO chatModelDO = convert(chatModel);
chatModelDO.setUpdatedBy(user.getName()); chatModelDO.setUpdatedBy(user.getName());
chatModelDO.setUpdatedAt(new Date()); chatModelDO.setUpdatedAt(new Date());
chatModelDO.setIsOpen(chatModel.getIsOpen());
if (StringUtils.isBlank(chatModel.getAdmin())) { if (StringUtils.isBlank(chatModel.getAdmin())) {
chatModel.setAdmin(user.getName()); chatModel.setAdmin(user.getName());
} }
if (!chatModel.getViewers().isEmpty()) {
chatModelDO.setViewer(JsonUtil.toString(chatModel.getViewers()));
}
updateById(chatModelDO); updateById(chatModelDO);
return chatModel; return chatModel;
} }
@@ -74,6 +89,7 @@ public class ChatModelServiceImpl extends ServiceImpl<ChatModelMapper, ChatModel
ChatModel chatModel = new ChatModel(); ChatModel chatModel = new ChatModel();
BeanUtils.copyProperties(chatModelDO, chatModel); BeanUtils.copyProperties(chatModelDO, chatModel);
chatModel.setConfig(JsonUtil.toObject(chatModelDO.getConfig(), ChatModelConfig.class)); chatModel.setConfig(JsonUtil.toObject(chatModelDO.getConfig(), ChatModelConfig.class));
chatModel.setViewers(JsonUtil.toList(chatModelDO.getViewer(), String.class));
return chatModel; return chatModel;
} }

View File

@@ -49,7 +49,8 @@ public class EmbeddingServiceImpl implements EmbeddingService {
try { try {
EmbeddingModel embeddingModel = ModelProvider.getEmbeddingModel(); EmbeddingModel embeddingModel = ModelProvider.getEmbeddingModel();
Embedding embedding = embeddingModel.embed(question).content(); Embedding embedding = embeddingModel.embed(question).content();
boolean existSegment = existSegment(embeddingStore, query, embedding); boolean existSegment =
existSegment(collectionName, embeddingStore, query, embedding);
if (existSegment) { if (existSegment) {
continue; continue;
} }
@@ -62,14 +63,14 @@ public class EmbeddingServiceImpl implements EmbeddingService {
} }
} }
private boolean existSegment(EmbeddingStore embeddingStore, TextSegment query, private boolean existSegment(String collectionName, EmbeddingStore embeddingStore,
Embedding embedding) { TextSegment query, Embedding embedding) {
String queryId = TextSegmentConvert.getQueryId(query); String queryId = TextSegmentConvert.getQueryId(query);
if (queryId == null) { if (queryId == null) {
return false; return false;
} }
// Check cache first // Check cache first
Boolean cachedResult = cache.getIfPresent(queryId); Boolean cachedResult = cache.getIfPresent(collectionName + queryId);
if (cachedResult != null) { if (cachedResult != null) {
return cachedResult; return cachedResult;
} }
@@ -82,7 +83,7 @@ public class EmbeddingServiceImpl implements EmbeddingService {
EmbeddingSearchResult result = embeddingStore.search(request); EmbeddingSearchResult result = embeddingStore.search(request);
List<EmbeddingMatch<TextSegment>> relevant = result.matches(); List<EmbeddingMatch<TextSegment>> relevant = result.matches();
boolean exists = CollectionUtils.isNotEmpty(relevant); boolean exists = CollectionUtils.isNotEmpty(relevant);
cache.put(queryId, exists); cache.put(collectionName + queryId, exists);
return exists; return exists;
} }

View File

@@ -1,9 +1,9 @@
package dev.langchain4j.inmemory.spring; package dev.langchain4j.inmemory.spring;
import dev.langchain4j.model.embedding.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.model.embedding.BgeSmallZhEmbeddingModel;
import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.S2OnnxEmbeddingModel; import dev.langchain4j.model.embedding.S2OnnxEmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.model.embedding.onnx.bgesmallzh.BgeSmallZhEmbeddingModel;
import dev.langchain4j.provider.EmbeddingModelConstant; import dev.langchain4j.provider.EmbeddingModelConstant;
import dev.langchain4j.store.embedding.EmbeddingStoreFactory; import dev.langchain4j.store.embedding.EmbeddingStoreFactory;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;

View File

@@ -1,5 +1,8 @@
package dev.langchain4j.model.embedding; package dev.langchain4j.model.embedding;
import dev.langchain4j.model.embedding.onnx.AbstractInProcessEmbeddingModel;
import dev.langchain4j.model.embedding.onnx.OnnxBertBiEncoder;
import dev.langchain4j.model.embedding.onnx.PoolingMode;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.IOException; import java.io.IOException;
@@ -9,6 +12,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executors;
/** /**
* An embedding model that runs within your Java application's process. Any BERT-based model (e.g., * An embedding model that runs within your Java application's process. Any BERT-based model (e.g.,
@@ -25,6 +29,7 @@ public class S2OnnxEmbeddingModel extends AbstractInProcessEmbeddingModel {
private static volatile String cachedVocabularyPath; private static volatile String cachedVocabularyPath;
public S2OnnxEmbeddingModel(String pathToModel, String vocabularyPath) { public S2OnnxEmbeddingModel(String pathToModel, String vocabularyPath) {
super(Executors.newSingleThreadExecutor());
if (shouldReloadModel(pathToModel, vocabularyPath)) { if (shouldReloadModel(pathToModel, vocabularyPath)) {
synchronized (S2OnnxEmbeddingModel.class) { synchronized (S2OnnxEmbeddingModel.class) {
if (shouldReloadModel(pathToModel, vocabularyPath)) { if (shouldReloadModel(pathToModel, vocabularyPath)) {
@@ -61,8 +66,8 @@ public class S2OnnxEmbeddingModel extends AbstractInProcessEmbeddingModel {
static OnnxBertBiEncoder loadFromFileSystem(Path pathToModel, URL vocabularyFile) { static OnnxBertBiEncoder loadFromFileSystem(Path pathToModel, URL vocabularyFile) {
try { try {
return new OnnxBertBiEncoder(Files.newInputStream(pathToModel), vocabularyFile, return new OnnxBertBiEncoder(Files.newInputStream(pathToModel),
PoolingMode.MEAN); vocabularyFile.openStream(), PoolingMode.MEAN);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@@ -1,8 +1,8 @@
package dev.langchain4j.provider; package dev.langchain4j.provider;
import dev.langchain4j.model.embedding.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.model.embedding.BgeSmallZhEmbeddingModel;
import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.model.embedding.onnx.bgesmallzh.BgeSmallZhEmbeddingModel;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service

View File

@@ -57,6 +57,7 @@ public class MilvusEmbeddingStore implements EmbeddingStore<TextSegment> {
private final ConsistencyLevelEnum consistencyLevel; private final ConsistencyLevelEnum consistencyLevel;
private final boolean retrieveEmbeddingsOnSearch; private final boolean retrieveEmbeddingsOnSearch;
private final boolean autoFlushOnInsert; private final boolean autoFlushOnInsert;
private final FieldDefinition fieldDefinition;
public MilvusEmbeddingStore(String host, Integer port, String collectionName, Integer dimension, public MilvusEmbeddingStore(String host, Integer port, String collectionName, Integer dimension,
IndexType indexType, MetricType metricType, String uri, String token, String username, IndexType indexType, MetricType metricType, String uri, String token, String username,
@@ -78,11 +79,15 @@ public class MilvusEmbeddingStore implements EmbeddingStore<TextSegment> {
this.retrieveEmbeddingsOnSearch = getOrDefault(retrieveEmbeddingsOnSearch, false); this.retrieveEmbeddingsOnSearch = getOrDefault(retrieveEmbeddingsOnSearch, false);
this.autoFlushOnInsert = getOrDefault(autoFlushOnInsert, false); this.autoFlushOnInsert = getOrDefault(autoFlushOnInsert, false);
// Define the field structure for the collection
this.fieldDefinition = new FieldDefinition(ID_FIELD_NAME, TEXT_FIELD_NAME,
METADATA_FIELD_NAME, VECTOR_FIELD_NAME);
if (!hasCollection(this.milvusClient, this.collectionName)) { if (!hasCollection(this.milvusClient, this.collectionName)) {
createCollection(this.milvusClient, this.collectionName, createCollection(this.milvusClient, this.collectionName, fieldDefinition,
ensureNotNull(dimension, "dimension")); ensureNotNull(dimension, "dimension"));
createIndex(this.milvusClient, this.collectionName, getOrDefault(indexType, FLAT), createIndex(this.milvusClient, this.collectionName, VECTOR_FIELD_NAME,
this.metricType); getOrDefault(indexType, FLAT), this.metricType);
} }
loadCollectionInMemory(this.milvusClient, collectionName); loadCollectionInMemory(this.milvusClient, collectionName);
@@ -128,7 +133,7 @@ public class MilvusEmbeddingStore implements EmbeddingStore<TextSegment> {
public EmbeddingSearchResult<TextSegment> search( public EmbeddingSearchResult<TextSegment> search(
EmbeddingSearchRequest embeddingSearchRequest) { EmbeddingSearchRequest embeddingSearchRequest) {
SearchParam searchParam = buildSearchRequest(collectionName, SearchParam searchParam = buildSearchRequest(collectionName, fieldDefinition,
embeddingSearchRequest.queryEmbedding().vectorAsList(), embeddingSearchRequest.queryEmbedding().vectorAsList(),
embeddingSearchRequest.filter(), embeddingSearchRequest.maxResults(), metricType, embeddingSearchRequest.filter(), embeddingSearchRequest.maxResults(), metricType,
consistencyLevel); consistencyLevel);
@@ -137,7 +142,7 @@ public class MilvusEmbeddingStore implements EmbeddingStore<TextSegment> {
CollectionOperationsExecutor.search(milvusClient, searchParam); CollectionOperationsExecutor.search(milvusClient, searchParam);
List<EmbeddingMatch<TextSegment>> matches = toEmbeddingMatches(milvusClient, resultsWrapper, List<EmbeddingMatch<TextSegment>> matches = toEmbeddingMatches(milvusClient, resultsWrapper,
collectionName, consistencyLevel, retrieveEmbeddingsOnSearch); collectionName, fieldDefinition, consistencyLevel, retrieveEmbeddingsOnSearch);
List<EmbeddingMatch<TextSegment>> result = List<EmbeddingMatch<TextSegment>> result =
matches.stream().filter(match -> match.score() >= embeddingSearchRequest.minScore()) matches.stream().filter(match -> match.score() >= embeddingSearchRequest.minScore())
@@ -226,7 +231,7 @@ public class MilvusEmbeddingStore implements EmbeddingStore<TextSegment> {
@Override @Override
public void removeAll(Filter filter) { public void removeAll(Filter filter) {
ensureNotNull(filter, "filter"); ensureNotNull(filter, "filter");
removeForVector(this.milvusClient, this.collectionName, map(filter)); removeForVector(this.milvusClient, this.collectionName, map(filter, METADATA_FIELD_NAME));
} }
/** /**

View File

@@ -2,7 +2,6 @@ package com.tencent.supersonic.common.calcite;
import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.common.pojo.enums.EngineType;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.sql.parser.SqlParseException;
import org.junit.Assert; import org.junit.Assert;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -12,7 +11,7 @@ import java.util.Collections;
class SqlWithMergerTest { class SqlWithMergerTest {
@Test @Test
void test1() throws SqlParseException { void test1() throws Exception {
String sql1 = "WITH DepartmentVisits AS (\n" + " SELECT department, SUM(pv) AS 总访问次数\n" String sql1 = "WITH DepartmentVisits AS (\n" + " SELECT department, SUM(pv) AS 总访问次数\n"
+ " FROM t_1\n" + " FROM t_1\n"
+ " WHERE sys_imp_date >= '2024-09-01' AND sys_imp_date <= '2024-09-29'\n" + " WHERE sys_imp_date >= '2024-09-01' AND sys_imp_date <= '2024-09-29'\n"
@@ -38,7 +37,7 @@ class SqlWithMergerTest {
} }
@Test @Test
void test2() throws SqlParseException { void test2() throws Exception {
String sql1 = String sql1 =
"WITH DepartmentVisits AS (SELECT department, SUM(pv) AS 总访问次数 FROM t_1 WHERE sys_imp_date >= '2024-08-28' " "WITH DepartmentVisits AS (SELECT department, SUM(pv) AS 总访问次数 FROM t_1 WHERE sys_imp_date >= '2024-08-28' "
@@ -65,7 +64,7 @@ class SqlWithMergerTest {
} }
@Test @Test
void test3() throws SqlParseException { void test3() throws Exception {
String sql1 = "SELECT COUNT(*) FROM DepartmentVisits WHERE 总访问次数 > 100 LIMIT 1000"; String sql1 = "SELECT COUNT(*) FROM DepartmentVisits WHERE 总访问次数 > 100 LIMIT 1000";
@@ -89,7 +88,7 @@ class SqlWithMergerTest {
} }
@Test @Test
void test4() throws SqlParseException { void test4() throws Exception {
String sql1 = "SELECT COUNT(*) FROM DepartmentVisits WHERE 总访问次数 > 100"; String sql1 = "SELECT COUNT(*) FROM DepartmentVisits WHERE 总访问次数 > 100";
String sql2 = String sql2 =
@@ -112,7 +111,7 @@ class SqlWithMergerTest {
} }
@Test @Test
void test5() throws SqlParseException { void test5() throws Exception {
String sql1 = "SELECT COUNT(*) FROM Department join Visits WHERE 总访问次数 > 100"; String sql1 = "SELECT COUNT(*) FROM Department join Visits WHERE 总访问次数 > 100";
@@ -132,13 +131,13 @@ class SqlWithMergerTest {
"WITH t_1 AS (SELECT `t3`.`sys_imp_date`, `t2`.`department`, `t3`.`s2_pv_uv_statis_pv` AS `pv` " "WITH t_1 AS (SELECT `t3`.`sys_imp_date`, `t2`.`department`, `t3`.`s2_pv_uv_statis_pv` AS `pv` "
+ "FROM (SELECT `user_name`, `department` FROM `s2_user_department`) AS `t2` LEFT JOIN " + "FROM (SELECT `user_name`, `department` FROM `s2_user_department`) AS `t2` LEFT JOIN "
+ "(SELECT 1 AS `s2_pv_uv_statis_pv`, `imp_date` AS `sys_imp_date`, `user_name` FROM `s2_pv_uv_statis`) " + "(SELECT 1 AS `s2_pv_uv_statis_pv`, `imp_date` AS `sys_imp_date`, `user_name` FROM `s2_pv_uv_statis`) "
+ "AS `t3` ON `t2`.`user_name` = `t3`.`user_name`) SELECT COUNT(*) FROM Department INNER JOIN Visits " + "AS `t3` ON `t2`.`user_name` = `t3`.`user_name`) SELECT COUNT(*) FROM Department JOIN Visits "
+ "WHERE 总访问次数 > 100"); + "WHERE 总访问次数 > 100");
} }
@Test @Test
void test6() throws SqlParseException { void test6() throws Exception {
String sql1 = String sql1 =
"SELECT COUNT(*) FROM Department join Visits WHERE 总访问次数 > 100 ORDER BY 总访问次数 LIMIT 10"; "SELECT COUNT(*) FROM Department join Visits WHERE 总访问次数 > 100 ORDER BY 总访问次数 LIMIT 10";
@@ -159,7 +158,36 @@ class SqlWithMergerTest {
"WITH t_1 AS (SELECT `t3`.`sys_imp_date`, `t2`.`department`, `t3`.`s2_pv_uv_statis_pv` AS `pv` FROM " "WITH t_1 AS (SELECT `t3`.`sys_imp_date`, `t2`.`department`, `t3`.`s2_pv_uv_statis_pv` AS `pv` FROM "
+ "(SELECT `user_name`, `department` FROM `s2_user_department`) AS `t2` LEFT JOIN (SELECT 1 AS `s2_pv_uv_statis_pv`," + "(SELECT `user_name`, `department` FROM `s2_user_department`) AS `t2` LEFT JOIN (SELECT 1 AS `s2_pv_uv_statis_pv`,"
+ " `imp_date` AS `sys_imp_date`, `user_name` FROM `s2_pv_uv_statis`) AS `t3` ON `t2`.`user_name` = `t3`.`user_name`) " + " `imp_date` AS `sys_imp_date`, `user_name` FROM `s2_pv_uv_statis`) AS `t3` ON `t2`.`user_name` = `t3`.`user_name`) "
+ "SELECT COUNT(*) FROM Department INNER JOIN Visits WHERE 总访问次数 > 100 ORDER BY 总访问次数 LIMIT 10"); + "SELECT COUNT(*) FROM Department JOIN Visits WHERE 总访问次数 > 100 ORDER BY 总访问次数 LIMIT 10");
}
@Test
void test7() throws Exception {
String sql1 =
"SELECT COUNT(*) FROM Department join Visits WHERE 总访问次数 > 100 AND imp_date >= CURRENT_DATE - "
+ "INTERVAL '1 year' AND sys_imp_date < CURRENT_DATE ORDER"
+ " BY 总访问次数 LIMIT 10";
String sql2 =
"SELECT `t3`.`sys_imp_date`, `t2`.`department`, `t3`.`s2_pv_uv_statis_pv` AS `pv`\n"
+ "FROM\n" + "(SELECT `user_name`, `department`\n" + "FROM\n"
+ "`s2_user_department`) AS `t2`\n"
+ "LEFT JOIN (SELECT 1 AS `s2_pv_uv_statis_pv`, `imp_date` AS `sys_imp_date`, `user_name`\n"
+ "FROM\n"
+ "`s2_pv_uv_statis`) AS `t3` ON `t2`.`user_name` = `t3`.`user_name`";
String mergeSql = SqlMergeWithUtils.mergeWith(EngineType.MYSQL, sql1,
Collections.singletonList(sql2), Collections.singletonList("t_1"));
Assert.assertEquals(format(mergeSql),
"WITH t_1 AS (SELECT `t3`.`sys_imp_date`, `t2`.`department`, `t3`.`s2_pv_uv_statis_pv` AS `pv` FROM "
+ "(SELECT `user_name`, `department` FROM `s2_user_department`) AS `t2` LEFT JOIN (SELECT 1 AS `s2_pv_uv_statis_pv`,"
+ " `imp_date` AS `sys_imp_date`, `user_name` FROM `s2_pv_uv_statis`) AS `t3` ON `t2`.`user_name` = `t3`.`user_name`) "
+ "SELECT COUNT(*) FROM Department JOIN Visits WHERE 总访问次数 > 100 AND imp_date >= "
+ "CURRENT_DATE - INTERVAL '1 year' AND sys_imp_date < CURRENT_DATE ORDER BY 总访问次数 "
+ "LIMIT 10");
} }
private static String format(String mergeSql) { private static String format(String mergeSql) {

View File

@@ -1,12 +1,8 @@
FROM supersonicbi/supersonic:0.9.10-SNAPSHOT FROM openjdk:21-jdk-bullseye as base
# Set the working directory in the container # Set the working directory in the container
WORKDIR /usr/src/app WORKDIR /usr/src/app
# Delete old supersonic installation directory and the symbolic link
RUN rm -rf /usr/src/app/supersonic-standalone-0.9.10-SNAPSHOT
RUN rm -f /usr/src/app/supersonic-standalone-latest
# Argument to pass in the supersonic version at build time # Argument to pass in the supersonic version at build time
ARG SUPERSONIC_VERSION ARG SUPERSONIC_VERSION
@@ -17,6 +13,17 @@ COPY assembly/build/supersonic-standalone-${SUPERSONIC_VERSION}.zip .
RUN unzip supersonic-standalone-${SUPERSONIC_VERSION}.zip && \ RUN unzip supersonic-standalone-${SUPERSONIC_VERSION}.zip && \
rm supersonic-standalone-${SUPERSONIC_VERSION}.zip rm supersonic-standalone-${SUPERSONIC_VERSION}.zip
FROM openjdk:21-slim
# Set the working directory in the container
WORKDIR /usr/src/app
# Argument to pass in the supersonic version at build time
ARG SUPERSONIC_VERSION
# Copy the supersonic standalone folder into the container
COPY --from=base /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION} ./supersonic-standalone-${SUPERSONIC_VERSION}
# Create a symbolic link to the supersonic installation directory # Create a symbolic link to the supersonic installation directory
RUN ln -s /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION} /usr/src/app/supersonic-standalone-latest RUN ln -s /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION} /usr/src/app/supersonic-standalone-latest
@@ -27,4 +34,4 @@ WORKDIR /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION}
EXPOSE 9080 EXPOSE 9080
# Command to run the supersonic daemon # Command to run the supersonic daemon
RUN chmod +x bin/supersonic-daemon.sh RUN chmod +x bin/supersonic-daemon.sh
CMD ["bash", "-c", "bin/supersonic-daemon.sh restart standalone docker && tail -f /dev/null"] CMD ["bash", "-c", "bin/supersonic-daemon.sh restart standalone ${S2_DB_TYPE} && tail -f /dev/null"]

View File

@@ -2,8 +2,8 @@
# Function to execute the build script # Function to execute the build script
execute_build_script() { execute_build_script() {
echo "Executing build script: assembly/bin/supersonic-build.sh" echo "Executing build script: sh assembly/bin/supersonic-build.sh"
assembly/bin/supersonic-build.sh sh assembly/bin/supersonic-build.sh
} }
# Function to build the Docker image # Function to build the Docker image

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env bash
SUPERSONIC_VERSION=latest docker-compose -f docker-compose.yml -p supersonic up

View File

@@ -11,8 +11,8 @@ services:
POSTGRES_PASSWORD: supersonic_password POSTGRES_PASSWORD: supersonic_password
ports: ports:
- "15432:5432" - "15432:5432"
# volumes: volumes:
# - postgres_data:/var/lib/postgresql - ./supersonic_pg/data:/var/lib/postgresql/data
networks: networks:
- supersonic_network - supersonic_network
dns: dns:
@@ -30,12 +30,19 @@ services:
privileged: true privileged: true
container_name: supersonic_standalone container_name: supersonic_standalone
environment: environment:
DB_HOST: supersonic_postgres S2_DB_TYPE: postgres
DB_NAME: postgres S2_DB_HOST: supersonic_postgres
DB_USERNAME: supersonic_user S2_DB_PORT: 5432
DB_PASSWORD: supersonic_password S2_DB_DATABASE: postgres
S2_DB_USER: supersonic_user
S2_DB_PASSWORD: supersonic_password
ports: ports:
- "9080:9080" - "9080:9080"
deploy:
resources:
limits:
cpus: "2.0"
memory: 2048M
depends_on: depends_on:
supersonic_postgres: supersonic_postgres:
condition: service_healthy condition: service_healthy
@@ -58,8 +65,7 @@ services:
# propagation: rprivate # propagation: rprivate
# create_host_path: true # create_host_path: true
#volumes: #volumes:
# postgres_data:
# supersonic_data: # supersonic_data:
networks: networks:
supersonic_network: supersonic_network:

View File

@@ -3,10 +3,12 @@ package com.tencent.supersonic.headless.api.pojo;
import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.headless.api.pojo.enums.DimensionType; import com.tencent.supersonic.headless.api.pojo.enums.DimensionType;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@Data @Data
@Builder
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class Dimension { public class Dimension {

View File

@@ -23,12 +23,16 @@ public class Measure {
private String alias; private String alias;
public Measure(String name, String bizName, String expr, String agg, Integer isCreateMetric) { private String unit;
public Measure(String name, String bizName, String expr, String agg, String unit,
Integer isCreateMetric) {
this.name = name; this.name = name;
this.agg = agg; this.agg = agg;
this.isCreateMetric = isCreateMetric; this.isCreateMetric = isCreateMetric;
this.bizName = bizName; this.bizName = bizName;
this.expr = expr; this.expr = expr;
this.unit = unit;
} }
public Measure(String name, String bizName, String agg, Integer isCreateMetric) { public Measure(String name, String bizName, String agg, Integer isCreateMetric) {

View File

@@ -24,6 +24,8 @@ public class ModelDetail {
private String tableQuery; private String tableQuery;
private String filterSql;
private List<Identify> identifiers = Lists.newArrayList(); private List<Identify> identifiers = Lists.newArrayList();
private List<Dimension> dimensions = Lists.newArrayList(); private List<Dimension> dimensions = Lists.newArrayList();
@@ -49,27 +51,4 @@ public class ModelDetail {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public List<Field> getFields() {
if (!CollectionUtils.isEmpty(fields)) {
return fields;
}
List<Field> fieldList = Lists.newArrayList();
// Compatible with older versions
if (!CollectionUtils.isEmpty(identifiers)) {
fieldList.addAll(identifiers.stream()
.map(identify -> Field.builder().fieldName(identify.getFieldName()).build())
.collect(Collectors.toSet()));
}
if (!CollectionUtils.isEmpty(dimensions)) {
fieldList.addAll(dimensions.stream()
.map(dim -> Field.builder().fieldName(dim.getFieldName()).build())
.collect(Collectors.toSet()));
}
if (!CollectionUtils.isEmpty(measures)) {
fieldList.addAll(measures.stream()
.map(measure -> Field.builder().fieldName(measure.getFieldName()).build())
.collect(Collectors.toSet()));
}
return fieldList;
}
} }

View File

@@ -14,11 +14,11 @@ public class ModelSchema {
private String description; private String description;
private List<ColumnSchema> columnSchemas; private List<SemanticColumn> semanticColumns;
@JsonIgnore @JsonIgnore
public ColumnSchema getColumnByName(String columnName) { public SemanticColumn getColumnByName(String columnName) {
for (ColumnSchema fieldSchema : columnSchemas) { for (SemanticColumn fieldSchema : semanticColumns) {
if (fieldSchema.getColumnName().equalsIgnoreCase(columnName)) { if (fieldSchema.getColumnName().equalsIgnoreCase(columnName)) {
return fieldSchema; return fieldSchema;
} }

View File

@@ -1,6 +1,5 @@
package com.tencent.supersonic.headless.api.pojo; package com.tencent.supersonic.headless.api.pojo;
import com.google.common.base.Objects;
import com.tencent.supersonic.common.pojo.RecordInfo; import com.tencent.supersonic.common.pojo.RecordInfo;
import com.tencent.supersonic.common.pojo.enums.SensitiveLevelEnum; import com.tencent.supersonic.common.pojo.enums.SensitiveLevelEnum;
import com.tencent.supersonic.common.pojo.enums.TypeEnums; import com.tencent.supersonic.common.pojo.enums.TypeEnums;
@@ -10,6 +9,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects;
@Data @Data
@ToString(callSuper = true) @ToString(callSuper = true)
@@ -40,13 +40,13 @@ public class SchemaItem extends RecordInfo {
return false; return false;
} }
SchemaItem that = (SchemaItem) o; SchemaItem that = (SchemaItem) o;
return Objects.equal(id, that.id) && Objects.equal(name, that.name) return Objects.equals(id, that.id) && Objects.equals(name, that.name)
&& Objects.equal(bizName, that.bizName) && typeEnum == that.typeEnum; && Objects.equals(bizName, that.bizName) && typeEnum == that.typeEnum;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(id, name, bizName, typeEnum); return Objects.hash(id, name, bizName, typeEnum);
} }
public static List<String> getAliasList(String alias) { public static List<String> getAliasList(String alias) {

View File

@@ -5,7 +5,7 @@ import com.tencent.supersonic.headless.api.pojo.enums.FieldType;
import lombok.Data; import lombok.Data;
@Data @Data
public class ColumnSchema { public class SemanticColumn {
private String columnName; private String columnName;
@@ -19,4 +19,8 @@ public class ColumnSchema {
private String name; private String name;
private String expr;
private String unit;
} }

View File

@@ -32,9 +32,12 @@ public class DatabaseReq extends RecordInfo {
private String description; private String description;
private String schema; private String schema;
private String url; private String url;
private List<String> admins = Lists.newArrayList(); private List<String> admins = Lists.newArrayList();
private List<String> viewers = Lists.newArrayList(); private List<String> viewers = Lists.newArrayList();
private Integer isOpen = 0;
} }

View File

@@ -19,6 +19,8 @@ public class ModelBuildReq {
private String sql; private String sql;
private String filterSql;
private String catalog; private String catalog;
private String db; private String db;

View File

@@ -30,6 +30,7 @@ public class QueryDataSetReq {
private List<Filter> metricFilters = new ArrayList<>(); private List<Filter> metricFilters = new ArrayList<>();
private DateConf dateInfo; private DateConf dateInfo;
private Long limit = 2000L; private Long limit = 2000L;
private Long offset = 0L;
private QueryType queryType = QueryType.DETAIL; private QueryType queryType = QueryType.DETAIL;
private boolean innerLayerNative = false; private boolean innerLayerNative = false;
} }

View File

@@ -3,11 +3,7 @@ package com.tencent.supersonic.headless.api.pojo.request;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.tencent.supersonic.common.jsqlparser.SqlAddHelper; import com.tencent.supersonic.common.jsqlparser.SqlAddHelper;
import com.tencent.supersonic.common.jsqlparser.SqlReplaceHelper; import com.tencent.supersonic.common.jsqlparser.SqlReplaceHelper;
import com.tencent.supersonic.common.pojo.Aggregator; import com.tencent.supersonic.common.pojo.*;
import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.common.pojo.DateConf;
import com.tencent.supersonic.common.pojo.Filter;
import com.tencent.supersonic.common.pojo.Order;
import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum; import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum;
import com.tencent.supersonic.common.pojo.enums.QueryType; import com.tencent.supersonic.common.pojo.enums.QueryType;
import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.ContextUtils;
@@ -25,12 +21,7 @@ import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.GroupByElement; import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.select.Limit;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SelectItem;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@@ -52,6 +43,7 @@ public class QueryStructReq extends SemanticQueryReq {
private List<Filter> metricFilters = new ArrayList<>(); private List<Filter> metricFilters = new ArrayList<>();
private DateConf dateInfo; private DateConf dateInfo;
private long limit = Constants.DEFAULT_DETAIL_LIMIT; private long limit = Constants.DEFAULT_DETAIL_LIMIT;
private long offset;
private QueryType queryType = QueryType.DETAIL; private QueryType queryType = QueryType.DETAIL;
private boolean convertToSql = true; private boolean convertToSql = true;
@@ -170,9 +162,15 @@ public class QueryStructReq extends SemanticQueryReq {
// 5. Set the limit clause // 5. Set the limit clause
plainSelect.setLimit(buildLimit(queryStructReq)); plainSelect.setLimit(buildLimit(queryStructReq));
// 6. Set the offset clause
plainSelect.setOffset(buildOffset(queryStructReq));
// 7. Set the having clause
plainSelect.setHaving(buildHavingClause(queryStructReq));
select.setSelect(plainSelect); select.setSelect(plainSelect);
// 6. Set where clause // 8. Set the where clause
return addWhereClauses(select.toString(), queryStructReq, isBizName); return addWhereClauses(select.toString(), queryStructReq, isBizName);
} }
@@ -239,7 +237,8 @@ public class QueryStructReq extends SemanticQueryReq {
private GroupByElement buildGroupByElement(QueryStructReq queryStructReq) { private GroupByElement buildGroupByElement(QueryStructReq queryStructReq) {
List<String> groups = queryStructReq.getGroups(); List<String> groups = queryStructReq.getGroups();
if (!CollectionUtils.isEmpty(groups) && !queryStructReq.getAggregators().isEmpty()) { if ((!CollectionUtils.isEmpty(groups) && !queryStructReq.getAggregators().isEmpty())
|| !queryStructReq.getMetricFilters().isEmpty()) {
GroupByElement groupByElement = new GroupByElement(); GroupByElement groupByElement = new GroupByElement();
for (String group : groups) { for (String group : groups) {
groupByElement.addGroupByExpression(new Column(group)); groupByElement.addGroupByExpression(new Column(group));
@@ -258,6 +257,15 @@ public class QueryStructReq extends SemanticQueryReq {
return limit; return limit;
} }
private Offset buildOffset(QueryStructReq queryStructReq) {
if (Objects.isNull(queryStructReq.getOffset())) {
return null;
}
Offset offset = new Offset();
offset.setOffset(new LongValue(queryStructReq.getOffset()));
return offset;
}
private String addWhereClauses(String sql, QueryStructReq queryStructReq, boolean isBizName) private String addWhereClauses(String sql, QueryStructReq queryStructReq, boolean isBizName)
throws JSQLParserException { throws JSQLParserException {
SqlFilterUtils sqlFilterUtils = ContextUtils.getBean(SqlFilterUtils.class); SqlFilterUtils sqlFilterUtils = ContextUtils.getBean(SqlFilterUtils.class);
@@ -289,4 +297,23 @@ public class QueryStructReq extends SemanticQueryReq {
} }
return Constants.TABLE_PREFIX + StringUtils.join(modelIds, "_"); return Constants.TABLE_PREFIX + StringUtils.join(modelIds, "_");
} }
public Expression buildHavingClause(QueryStructReq queryStructReq) {
if (queryStructReq.getMetricFilters().isEmpty()) {
return null;
}
List<Filter> filters = queryStructReq.getMetricFilters();
SqlFilterUtils sqlFilterUtils = ContextUtils.getBean(SqlFilterUtils.class);
String havingClause = sqlFilterUtils.getWhereClause(filters, false);
if (StringUtils.isNotBlank(havingClause)) {
try {
return CCJSqlParserUtil.parseCondExpression(havingClause);
} catch (JSQLParserException e) {
log.error("Failed to parse having clause", e);
}
}
return null;
}
} }

View File

@@ -28,6 +28,8 @@ public class DatabaseResp extends RecordInfo {
private List<String> viewers = Lists.newArrayList(); private List<String> viewers = Lists.newArrayList();
private Integer isOpen = 0;
private String type; private String type;
private String url; private String url;
@@ -48,6 +50,10 @@ public class DatabaseResp extends RecordInfo {
private boolean hasEditPermission = false; private boolean hasEditPermission = false;
public boolean isPublic() {
return isOpen != null && isOpen == 1;
}
public String getHost() { public String getHost() {
Pattern p = Pattern.compile("jdbc:(?<db>\\w+):.*((//)|@)(?<host>.+):(?<port>\\d+).*"); Pattern p = Pattern.compile("jdbc:(?<db>\\w+):.*((//)|@)(?<host>.+):(?<port>\\d+).*");
Matcher m = p.matcher(url); Matcher m = p.matcher(url);

View File

@@ -53,4 +53,15 @@ public class DimensionResp extends SchemaItem {
public boolean isPartitionTime() { public boolean isPartitionTime() {
return DimensionType.isPartitionTime(type); return DimensionType.isPartitionTime(type);
} }
@Override
public boolean equals(Object o) {
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
} }

View File

@@ -10,10 +10,7 @@ import lombok.ToString;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Arrays; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Data @Data
@@ -118,4 +115,15 @@ public class MetricResp extends SchemaItem {
public boolean isDerived() { public boolean isDerived() {
return MetricType.isDerived(metricDefineType, metricDefineByMeasureParams); return MetricType.isDerived(metricDefineType, metricDefineByMeasureParams);
} }
@Override
public boolean equals(Object o) {
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
} }

View File

@@ -1,12 +1,16 @@
package com.tencent.supersonic.headless.chat.corrector; package com.tencent.supersonic.headless.chat.corrector;
import com.tencent.supersonic.common.util.ContextUtils;
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo; import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
import com.tencent.supersonic.headless.chat.ChatQueryContext; import com.tencent.supersonic.headless.chat.ChatQueryContext;
import com.tencent.supersonic.headless.chat.parser.ParserConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.tencent.supersonic.headless.chat.parser.ParserConfig.PARSER_RULE_CORRECTOR_ENABLE;
@Slf4j @Slf4j
public class RuleSqlCorrector extends BaseSemanticCorrector { public class RuleSqlCorrector extends BaseSemanticCorrector {
private List<BaseSemanticCorrector> correctors; private List<BaseSemanticCorrector> correctors;
@@ -20,6 +24,11 @@ public class RuleSqlCorrector extends BaseSemanticCorrector {
@Override @Override
public void doCorrect(ChatQueryContext chatQueryContext, SemanticParseInfo semanticParseInfo) { public void doCorrect(ChatQueryContext chatQueryContext, SemanticParseInfo semanticParseInfo) {
ParserConfig parserConfig = ContextUtils.getBean(ParserConfig.class);
if (!Boolean.parseBoolean(parserConfig.getParameterValue(PARSER_RULE_CORRECTOR_ENABLE))) {
return;
}
for (BaseSemanticCorrector corrector : correctors) { for (BaseSemanticCorrector corrector : correctors) {
corrector.correct(chatQueryContext, semanticParseInfo); corrector.correct(chatQueryContext, semanticParseInfo);
} }

View File

@@ -1,5 +1,6 @@
package com.tencent.supersonic.headless.chat.corrector; package com.tencent.supersonic.headless.chat.corrector;
import com.tencent.supersonic.common.jsqlparser.FieldExpression;
import com.tencent.supersonic.common.jsqlparser.SqlAddHelper; import com.tencent.supersonic.common.jsqlparser.SqlAddHelper;
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper; import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
import com.tencent.supersonic.common.jsqlparser.SqlValidHelper; import com.tencent.supersonic.common.jsqlparser.SqlValidHelper;
@@ -8,10 +9,7 @@ import com.tencent.supersonic.headless.chat.ChatQueryContext;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/** Perform SQL corrections on the "Select" section in S2SQL. */ /** Perform SQL corrections on the "Select" section in S2SQL. */
@Slf4j @Slf4j
@@ -46,10 +44,28 @@ public class SelectCorrector extends BaseSemanticCorrector {
return correctS2SQL; return correctS2SQL;
} }
needAddFields.removeAll(selectFields); needAddFields.removeAll(selectFields);
String addFieldsToSelectSql =
SqlAddHelper.addFieldsToSelect(correctS2SQL, new ArrayList<>(needAddFields)); if (!SqlSelectHelper.hasSubSelect(correctS2SQL)) { // 优化内容 如果sql 条件包含了这个字段,而且是全等,则不再查询该字段
semanticParseInfo.getSqlInfo().setCorrectedS2SQL(addFieldsToSelectSql); List<FieldExpression> tmp4 = SqlSelectHelper.getWhereExpressions(correctS2SQL);
return addFieldsToSelectSql; Iterator<String> it = needAddFields.iterator();
while (it.hasNext()) {
String field = it.next();
long size = tmp4.stream()
.filter(e -> e.getFieldName().equals(field) && "=".equals(e.getOperator()))
.count();
if (size == 1) {
it.remove();
}
}
}
if (needAddFields.size() > 0) {
String addFieldsToSelectSql =
SqlAddHelper.addFieldsToSelect(correctS2SQL, new ArrayList<>(needAddFields));
semanticParseInfo.getSqlInfo().setCorrectedS2SQL(addFieldsToSelectSql);
return addFieldsToSelectSql;
} else {
return correctS2SQL;
}
} }
} }

View File

@@ -22,4 +22,9 @@ public abstract class MapResult implements Serializable {
return this.getMapKey().equals(otherResult.getMapKey()) return this.getMapKey().equals(otherResult.getMapKey())
&& this.similarity < otherResult.similarity; && this.similarity < otherResult.similarity;
} }
public Boolean lessOrEqualSimilar(MapResult otherResult) {
return this.getMapKey().equals(otherResult.getMapKey())
&& this.similarity <= otherResult.similarity;
}
} }

View File

@@ -75,6 +75,8 @@ public class MetaEmbeddingService {
return dataSetIds.stream().map(dataSetId -> { return dataSetIds.stream().map(dataSetId -> {
Retrieval newRetrieval = new Retrieval(); Retrieval newRetrieval = new Retrieval();
BeanUtils.copyProperties(retrieval, newRetrieval); BeanUtils.copyProperties(retrieval, newRetrieval);
HashMap<String, Object> newMetadata = new HashMap<>(retrieval.getMetadata());
newRetrieval.setMetadata(newMetadata);
newRetrieval.getMetadata().putIfAbsent("dataSetId", newRetrieval.getMetadata().putIfAbsent("dataSetId",
dataSetId + Constants.UNDERLINE); dataSetId + Constants.UNDERLINE);
return newRetrieval; return newRetrieval;

View File

@@ -56,7 +56,7 @@ public abstract class BaseMatchStrategy<T extends MapResult> implements MatchStr
for (T oneRoundResult : oneRoundResults) { for (T oneRoundResult : oneRoundResults) {
if (existResults.contains(oneRoundResult)) { if (existResults.contains(oneRoundResult)) {
boolean isDeleted = existResults.removeIf(existResult -> { boolean isDeleted = existResults.removeIf(existResult -> {
boolean delete = existResult.lessSimilar(oneRoundResult); boolean delete = existResult.lessOrEqualSimilar(oneRoundResult);
if (delete) { if (delete) {
log.debug("deleted existResult:{}", existResult); log.debug("deleted existResult:{}", existResult);
} }

View File

@@ -75,6 +75,9 @@ public class KeywordMapper extends BaseMapper {
continue; continue;
} }
Long elementID = NatureHelper.getElementID(nature); Long elementID = NatureHelper.getElementID(nature);
if (elementID == null) {
continue;
}
SchemaElement element = getSchemaElement(dataSetId, elementType, elementID, SchemaElement element = getSchemaElement(dataSetId, elementType, elementID,
chatQueryContext.getSemanticSchema()); chatQueryContext.getSemanticSchema());
if (Objects.isNull(element)) { if (Objects.isNull(element)) {

View File

@@ -17,6 +17,10 @@ public class ParserConfig extends ParameterConfig {
"ONE_PASS_SELF_CONSISTENCY: 通过投票方式一步生成sql", "list", "语义解析配置", "ONE_PASS_SELF_CONSISTENCY: 通过投票方式一步生成sql", "list", "语义解析配置",
Lists.newArrayList("ONE_PASS_SELF_CONSISTENCY")); Lists.newArrayList("ONE_PASS_SELF_CONSISTENCY"));
public static final Parameter PARSER_RULE_CORRECTOR_ENABLE =
new Parameter("s2.parser.rule.corrector.enable", "false", "是否开启规则修正器",
"规则修正器灵活度有限,在大模型能力足够情况下,不必强制做规则修正", "bool", "语义解析配置");
public static final Parameter PARSER_LINKING_VALUE_ENABLE = public static final Parameter PARSER_LINKING_VALUE_ENABLE =
new Parameter("s2.parser.linking.value.enable", "true", "是否将Mapper探测识别到的维度值提供给大模型", new Parameter("s2.parser.linking.value.enable", "true", "是否将Mapper探测识别到的维度值提供给大模型",
"为了数据安全考虑, 这里可进行开关选择", "bool", "语义解析配置"); "为了数据安全考虑, 这里可进行开关选择", "bool", "语义解析配置");
@@ -55,7 +59,8 @@ public class ParserConfig extends ParameterConfig {
@Override @Override
public List<Parameter> getSysParameters() { public List<Parameter> getSysParameters() {
return Lists.newArrayList(PARSER_LINKING_VALUE_ENABLE, PARSER_FEW_SHOT_NUMBER, return Lists.newArrayList(PARSER_LINKING_VALUE_ENABLE, PARSER_RULE_CORRECTOR_ENABLE,
PARSER_SELF_CONSISTENCY_NUMBER, PARSER_SHOW_COUNT, PARSER_FIELDS_COUNT_THRESHOLD); PARSER_FEW_SHOT_NUMBER, PARSER_SELF_CONSISTENCY_NUMBER, PARSER_SHOW_COUNT,
PARSER_FIELDS_COUNT_THRESHOLD);
} }
} }

View File

@@ -33,15 +33,14 @@ public class PromptHelper {
public List<List<Text2SQLExemplar>> getFewShotExemplars(LLMReq llmReq) { public List<List<Text2SQLExemplar>> getFewShotExemplars(LLMReq llmReq) {
int exemplarRecallNumber = int exemplarRecallNumber =
Integer.valueOf(parserConfig.getParameterValue(PARSER_EXEMPLAR_RECALL_NUMBER)); Integer.parseInt(parserConfig.getParameterValue(PARSER_EXEMPLAR_RECALL_NUMBER));
int fewShotNumber = Integer.valueOf(parserConfig.getParameterValue(PARSER_FEW_SHOT_NUMBER)); int fewShotNumber =
Integer.parseInt(parserConfig.getParameterValue(PARSER_FEW_SHOT_NUMBER));
int selfConsistencyNumber = int selfConsistencyNumber =
Integer.valueOf(parserConfig.getParameterValue(PARSER_SELF_CONSISTENCY_NUMBER)); Integer.parseInt(parserConfig.getParameterValue(PARSER_SELF_CONSISTENCY_NUMBER));
List<Text2SQLExemplar> exemplars = Lists.newArrayList(); List<Text2SQLExemplar> exemplars = Lists.newArrayList();
llmReq.getDynamicExemplars().stream().forEach(e -> { exemplars.addAll(llmReq.getDynamicExemplars());
exemplars.add(e);
});
int recallSize = exemplarRecallNumber - llmReq.getDynamicExemplars().size(); int recallSize = exemplarRecallNumber - llmReq.getDynamicExemplars().size();
if (recallSize > 0) { if (recallSize > 0) {
@@ -85,60 +84,64 @@ public class PromptHelper {
String tableStr = llmReq.getSchema().getDataSetName(); String tableStr = llmReq.getSchema().getDataSetName();
List<String> metrics = Lists.newArrayList(); List<String> metrics = Lists.newArrayList();
llmReq.getSchema().getMetrics().stream().forEach(metric -> { llmReq.getSchema().getMetrics().forEach(metric -> {
StringBuilder metricStr = new StringBuilder(); StringBuilder metricStr = new StringBuilder();
metricStr.append("<"); metricStr.append("<");
metricStr.append(metric.getName()); metricStr.append(metric.getName());
if (!CollectionUtils.isEmpty(metric.getAlias())) { if (!CollectionUtils.isEmpty(metric.getAlias())) {
StringBuilder alias = new StringBuilder(); StringBuilder alias = new StringBuilder();
metric.getAlias().stream().forEach(a -> alias.append(a + ",")); metric.getAlias().forEach(a -> alias.append(a).append(","));
metricStr.append(" ALIAS '" + alias + "'"); metricStr.append(" ALIAS '").append(alias).append("'");
} }
if (StringUtils.isNotEmpty(metric.getDataFormatType())) { if (StringUtils.isNotEmpty(metric.getDataFormatType())) {
String dataFormatType = metric.getDataFormatType(); String dataFormatType = metric.getDataFormatType();
if (DataFormatTypeEnum.DECIMAL.getName().equalsIgnoreCase(dataFormatType) if (DataFormatTypeEnum.DECIMAL.getName().equalsIgnoreCase(dataFormatType)
|| DataFormatTypeEnum.PERCENT.getName().equalsIgnoreCase(dataFormatType)) { || DataFormatTypeEnum.PERCENT.getName().equalsIgnoreCase(dataFormatType)) {
metricStr.append(" FORMAT '" + dataFormatType + "'"); metricStr.append(" FORMAT '").append(dataFormatType).append("'");
} }
} }
if (StringUtils.isNotEmpty(metric.getDescription())) { if (StringUtils.isNotEmpty(metric.getDescription())) {
metricStr.append(" COMMENT '" + metric.getDescription() + "'"); metricStr.append(" COMMENT '").append(metric.getDescription()).append("'");
} }
if (StringUtils.isNotEmpty(metric.getDefaultAgg())) { if (StringUtils.isNotEmpty(metric.getDefaultAgg())) {
metricStr.append(" AGGREGATE '" + metric.getDefaultAgg().toUpperCase() + "'"); metricStr.append(" AGGREGATE '").append(metric.getDefaultAgg().toUpperCase())
.append("'");
} }
metricStr.append(">"); metricStr.append(">");
metrics.add(metricStr.toString()); metrics.add(metricStr.toString());
}); });
List<String> dimensions = Lists.newArrayList(); List<String> dimensions = Lists.newArrayList();
llmReq.getSchema().getDimensions().stream().forEach(dimension -> { llmReq.getSchema().getDimensions().forEach(dimension -> {
StringBuilder dimensionStr = new StringBuilder(); StringBuilder dimensionStr = new StringBuilder();
dimensionStr.append("<"); dimensionStr.append("<");
dimensionStr.append(dimension.getName()); dimensionStr.append(dimension.getName());
if (!CollectionUtils.isEmpty(dimension.getAlias())) { if (!CollectionUtils.isEmpty(dimension.getAlias())) {
StringBuilder alias = new StringBuilder(); StringBuilder alias = new StringBuilder();
dimension.getAlias().stream().forEach(a -> alias.append(a + ";")); dimension.getAlias().forEach(a -> alias.append(a).append(";"));
dimensionStr.append(" ALIAS '" + alias + "'"); dimensionStr.append(" ALIAS '").append(alias).append("'");
} }
if (StringUtils.isNotEmpty(dimension.getTimeFormat())) { if (StringUtils.isNotEmpty(dimension.getTimeFormat())) {
dimensionStr.append(" FORMAT '" + dimension.getTimeFormat() + "'"); dimensionStr.append(" FORMAT '").append(dimension.getTimeFormat()).append("'");
} }
if (StringUtils.isNotEmpty(dimension.getDescription())) { if (StringUtils.isNotEmpty(dimension.getDescription())) {
dimensionStr.append(" COMMENT '" + dimension.getDescription() + "'"); dimensionStr.append(" COMMENT '").append(dimension.getDescription()).append("'");
} }
dimensionStr.append(">"); dimensionStr.append(">");
dimensions.add(dimensionStr.toString()); dimensions.add(dimensionStr.toString());
}); });
List<String> values = Lists.newArrayList(); List<String> values = Lists.newArrayList();
llmReq.getSchema().getValues().stream().forEach(value -> { List<LLMReq.ElementValue> elementValueList = llmReq.getSchema().getValues();
StringBuilder valueStr = new StringBuilder(); if (elementValueList != null) {
String fieldName = value.getFieldName(); elementValueList.forEach(value -> {
String fieldValue = value.getFieldValue(); StringBuilder valueStr = new StringBuilder();
valueStr.append(String.format("<%s='%s'>", fieldName, fieldValue)); String fieldName = value.getFieldName();
values.add(valueStr.toString()); String fieldValue = value.getFieldValue();
}); valueStr.append(String.format("<%s='%s'>", fieldName, fieldValue));
values.add(valueStr.toString());
});
}
String partitionTimeStr = ""; String partitionTimeStr = "";
if (llmReq.getSchema().getPartitionTime() != null) { if (llmReq.getSchema().getPartitionTime() != null) {
@@ -172,14 +175,14 @@ public class PromptHelper {
private String buildTermStr(LLMReq llmReq) { private String buildTermStr(LLMReq llmReq) {
List<LLMReq.Term> terms = llmReq.getTerms(); List<LLMReq.Term> terms = llmReq.getTerms();
List<String> termStr = Lists.newArrayList(); List<String> termStr = Lists.newArrayList();
terms.stream().forEach(term -> { terms.forEach(term -> {
StringBuilder termsDesc = new StringBuilder(); StringBuilder termsDesc = new StringBuilder();
String description = term.getDescription(); String description = term.getDescription();
termsDesc.append(String.format("<%s COMMENT '%s'>", term.getName(), description)); termsDesc.append(String.format("<%s COMMENT '%s'>", term.getName(), description));
termStr.add(termsDesc.toString()); termStr.add(termsDesc.toString());
}); });
String ret = ""; String ret = "";
if (termStr.size() > 0) { if (!termStr.isEmpty()) {
ret = String.join(",", termStr); ret = String.join(",", termStr);
} }

View File

@@ -41,6 +41,28 @@ class AggCorrectorTest {
semanticParseInfo.getSqlInfo().getCorrectedS2SQL()); semanticParseInfo.getSqlInfo().getCorrectedS2SQL());
} }
@Test
void testSchemaCorrector() {
SchemaCorrector corrector = new SchemaCorrector();
Long dataSetId = 1L;
ChatQueryContext chatQueryContext = buildQueryContext(dataSetId);
SemanticParseInfo semanticParseInfo = new SemanticParseInfo();
SchemaElement dataSet = new SchemaElement();
dataSet.setDataSetId(dataSetId);
semanticParseInfo.setDataSet(dataSet);
SqlInfo sqlInfo = new SqlInfo();
String sql =
"WITH 总停留时长 AS (SELECT 用户, SUM(停留时长) AS _总停留时长_ FROM 超音数数据集 WHERE 用户 IN ('alice', 'lucy') AND 数据日期 >= '2025-03-01' AND 数据日期 <= '2025-03-12' GROUP BY 用户) SELECT 用户, _总停留时长_ FROM 总停留时长";
sqlInfo.setParsedS2SQL(sql);
sqlInfo.setCorrectedS2SQL(sql);
semanticParseInfo.setSqlInfo(sqlInfo);
corrector.correct(chatQueryContext, semanticParseInfo);
Assert.assertEquals(
"WITH 总停留时长 AS (SELECT 用户名, SUM(停留时长) AS _总停留时长_ FROM 超音数数据集 WHERE 用户名 IN ('alice', 'lucy') AND 数据日期 "
+ ">= '2025-03-01' AND 数据日期 <= '2025-03-12' GROUP BY 用户名) SELECT 用户名, _总停留时长_ FROM 总停留时长",
semanticParseInfo.getSqlInfo().getCorrectedS2SQL());
}
private ChatQueryContext buildQueryContext(Long dataSetId) { private ChatQueryContext buildQueryContext(Long dataSetId) {
ChatQueryContext chatQueryContext = new ChatQueryContext(); ChatQueryContext chatQueryContext = new ChatQueryContext();
List<DataSetSchema> dataSetSchemaList = new ArrayList<>(); List<DataSetSchema> dataSetSchemaList = new ArrayList<>();
@@ -51,18 +73,18 @@ class AggCorrectorTest {
schemaElement.setDataSetId(dataSetId); schemaElement.setDataSetId(dataSetId);
dataSetSchema.setDataSet(schemaElement); dataSetSchema.setDataSet(schemaElement);
Set<SchemaElement> dimensions = new HashSet<>(); Set<SchemaElement> dimensions = new HashSet<>();
SchemaElement element1 = new SchemaElement();
element1.setDataSetId(1L); dimensions.add(SchemaElement.builder().dataSetId(1L).name("部门").build());
element1.setName("部门");
dimensions.add(element1); dimensions.add(SchemaElement.builder().dataSetId(1L).name("用户名").build());
dataSetSchema.setDimensions(dimensions); dataSetSchema.setDimensions(dimensions);
Set<SchemaElement> metrics = new HashSet<>(); Set<SchemaElement> metrics = new HashSet<>();
SchemaElement metric1 = new SchemaElement();
metric1.setDataSetId(1L); metrics.add(SchemaElement.builder().dataSetId(1L).name("访问次数").build());
metric1.setName("访问次数");
metrics.add(metric1); metrics.add(SchemaElement.builder().dataSetId(1L).name("停留时长").build());
dataSetSchema.setMetrics(metrics); dataSetSchema.setMetrics(metrics);
dataSetSchemaList.add(dataSetSchema); dataSetSchemaList.add(dataSetSchema);

View File

@@ -64,7 +64,7 @@
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId> <artifactId>transmittable-thread-local</artifactId>
<version>${transmittable.thread.local.version}</version> <version>${transmittable.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.aspectj</groupId> <groupId>org.aspectj</groupId>

View File

@@ -10,6 +10,7 @@ import org.apache.commons.lang3.StringUtils;
import java.sql.*; import java.sql.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Properties; import java.util.Properties;
@Slf4j @Slf4j
@@ -149,15 +150,17 @@ public abstract class BaseDbAdaptor implements DbAdaptor {
// 设置通用属性 // 设置通用属性
properties.setProperty("user", connectionInfo.getUserName()); properties.setProperty("user", connectionInfo.getUserName());
String password = Optional.ofNullable(connectionInfo.getPassword()).orElse("");
// 针对 Presto 和 Trino ssl=false 的情况,不需要设置密码 // 针对 Presto 和 Trino ssl=false 的情况,不需要设置密码
if (url.startsWith("jdbc:presto") || url.startsWith("jdbc:trino")) { if (url.startsWith("jdbc:presto") || url.startsWith("jdbc:trino")) {
// 检查是否需要处理 SSL // 检查是否需要处理 SSL
if (!url.contains("ssl=false")) { if (!url.contains("ssl=false")) {
properties.setProperty("password", connectionInfo.getPassword()); properties.setProperty("password", password);
} }
} else { } else {
// 针对其他数据库类型 // 针对其他数据库类型
properties.setProperty("password", connectionInfo.getPassword()); properties.setProperty("password", password);
} }
return properties; return properties;

View File

@@ -88,7 +88,7 @@ public class PostgresqlAdaptor extends BaseDbAdaptor {
List<String> tablesAndViews = Lists.newArrayList(); List<String> tablesAndViews = Lists.newArrayList();
DatabaseMetaData metaData = getDatabaseMetaData(connectionInfo); DatabaseMetaData metaData = getDatabaseMetaData(connectionInfo);
try (ResultSet resultSet = try (ResultSet resultSet =
metaData.getTables(null, null, null, new String[] {"TABLE", "VIEW"})) { metaData.getTables(null, schemaName, null, new String[] {"TABLE", "VIEW"})) {
while (resultSet.next()) { while (resultSet.next()) {
String name = resultSet.getString("TABLE_NAME"); String name = resultSet.getString("TABLE_NAME");
tablesAndViews.add(name); tablesAndViews.add(name);
@@ -103,7 +103,7 @@ public class PostgresqlAdaptor extends BaseDbAdaptor {
String tableName) throws SQLException { String tableName) throws SQLException {
List<DBColumn> dbColumns = Lists.newArrayList(); List<DBColumn> dbColumns = Lists.newArrayList();
DatabaseMetaData metaData = getDatabaseMetaData(connectInfo); DatabaseMetaData metaData = getDatabaseMetaData(connectInfo);
ResultSet columns = metaData.getColumns(null, null, tableName, null); ResultSet columns = metaData.getColumns(null, schemaName, tableName, null);
while (columns.next()) { while (columns.next()) {
String columnName = columns.getString("COLUMN_NAME"); String columnName = columns.getString("COLUMN_NAME");
String dataType = columns.getString("TYPE_NAME"); String dataType = columns.getString("TYPE_NAME");

View File

@@ -83,6 +83,7 @@ public class PrestoAdaptor extends BaseDbAdaptor {
@Override @Override
public String rewriteSql(String sql) { public String rewriteSql(String sql) {
sql = sql.replaceAll("`", "\"");
return sql; return sql;
} }
} }

View File

@@ -20,6 +20,7 @@ public class StructQuery {
private List<Filter> metricFilters = new ArrayList(); private List<Filter> metricFilters = new ArrayList();
private DateConf dateInfo; private DateConf dateInfo;
private Long limit = 2000L; private Long limit = 2000L;
private Long offset = 0L;
private QueryType queryType; private QueryType queryType;
private List<Param> params = new ArrayList<>(); private List<Param> params = new ArrayList<>();
} }

View File

@@ -1,6 +1,7 @@
package com.tencent.supersonic.headless.core.translator; package com.tencent.supersonic.headless.core.translator;
import com.tencent.supersonic.common.calcite.SqlMergeWithUtils; import com.tencent.supersonic.common.calcite.SqlMergeWithUtils;
import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
import com.tencent.supersonic.common.pojo.enums.EngineType; import com.tencent.supersonic.common.pojo.enums.EngineType;
import com.tencent.supersonic.headless.api.pojo.response.QueryState; import com.tencent.supersonic.headless.api.pojo.response.QueryState;
import com.tencent.supersonic.headless.core.pojo.OntologyQuery; import com.tencent.supersonic.headless.core.pojo.OntologyQuery;
@@ -73,7 +74,7 @@ public class DefaultSemanticTranslator implements SemanticTranslator {
String finalSql = null; String finalSql = null;
if (sqlQuery.isSupportWith()) { if (sqlQuery.isSupportWith()) {
EngineType engineType = queryStatement.getOntology().getDatabaseType(); EngineType engineType = queryStatement.getOntology().getDatabaseType();
if (!SqlMergeWithUtils.hasWith(engineType, ontologyOuterSql)) { if (!SqlSelectHelper.hasWith(ontologyOuterSql)) {
finalSql = "with " + tables.stream() finalSql = "with " + tables.stream()
.map(t -> String.format("%s as (%s)", t.getLeft(), t.getRight())) .map(t -> String.format("%s as (%s)", t.getLeft(), t.getRight()))
.collect(Collectors.joining(",")) + "\n" + ontologyOuterSql; .collect(Collectors.joining(",")) + "\n" + ontologyOuterSql;

View File

@@ -40,11 +40,23 @@ public class DataModelNode extends SemanticNode {
.equalsIgnoreCase(EngineType.POSTGRESQL.getName())) { .equalsIgnoreCase(EngineType.POSTGRESQL.getName())) {
String fullTableName = String.join(".public.", String fullTableName = String.join(".public.",
dataModel.getModelDetail().getTableQuery().split("\\.")); dataModel.getModelDetail().getTableQuery().split("\\."));
sqlTable = "select * from " + fullTableName; sqlTable = "SELECT * FROM " + fullTableName;
} else { } else {
sqlTable = "select * from " + dataModel.getModelDetail().getTableQuery(); sqlTable = "SELECT * FROM " + dataModel.getModelDetail().getTableQuery();
} }
} }
// String filterSql = dataModel.getFilterSql();
String filterSql = dataModel.getModelDetail().getFilterSql();
if (filterSql != null && !filterSql.isEmpty()) {
boolean sqlContainWhere = sqlTable.toUpperCase().matches("(?s).*\\bWHERE\\b.*");
if (sqlContainWhere) {
sqlTable = String.format("%s AND %s", sqlTable, filterSql);
} else {
sqlTable = String.format("%s WHERE %s", sqlTable, filterSql);
}
}
if (sqlTable.isEmpty()) { if (sqlTable.isEmpty()) {
throw new Exception("DataModelNode build error [tableSqlNode not found]"); throw new Exception("DataModelNode build error [tableSqlNode not found]");
} }

View File

@@ -78,7 +78,8 @@ public abstract class SemanticNode {
scope.getValidator().getCatalogReader().getRootSchema(), engineType); scope.getValidator().getCatalogReader().getRootSchema(), engineType);
if (Configuration.getSqlAdvisor(sqlValidatorWithHints, engineType).getReservedAndKeyWords() if (Configuration.getSqlAdvisor(sqlValidatorWithHints, engineType).getReservedAndKeyWords()
.contains(expression.toUpperCase())) { .contains(expression.toUpperCase())) {
if (engineType == EngineType.HANADB) { if (engineType == EngineType.HANADB || engineType == EngineType.PRESTO
|| engineType == EngineType.TRINO) {
expression = String.format("\"%s\"", expression); expression = String.format("\"%s\"", expression);
} else { } else {
expression = String.format("`%s`", expression); expression = String.format("`%s`", expression);
@@ -166,9 +167,9 @@ public abstract class SemanticNode {
if (sqlNode instanceof SqlBasicCall) { if (sqlNode instanceof SqlBasicCall) {
SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode; SqlBasicCall sqlBasicCall = (SqlBasicCall) sqlNode;
if (sqlBasicCall.getOperator().getKind().equals(SqlKind.AS)) { if (sqlBasicCall.getOperator().getKind().equals(SqlKind.AS)) {
if (sqlBasicCall.getOperandList().get(0) instanceof SqlSelect) { SqlNode innerQuery = sqlBasicCall.getOperandList().get(0);
SqlSelect table = (SqlSelect) sqlBasicCall.getOperandList().get(0); if (innerQuery instanceof SqlCall) {
return table; return innerQuery;
} }
} }
} }

View File

@@ -69,7 +69,13 @@ public class SqlBuilder {
SqlNode parserNode = tableView.build(); SqlNode parserNode = tableView.build();
DatabaseResp database = queryStatement.getOntology().getDatabase(); DatabaseResp database = queryStatement.getOntology().getDatabase();
EngineType engineType = EngineType.fromString(database.getType()); EngineType engineType = EngineType.fromString(database.getType());
parserNode = optimizeParseNode(parserNode, engineType); try {
parserNode = optimizeParseNode(parserNode, engineType);
} catch (Exception e) {
// failure in optimization phase doesn't affect the query result,
// just ignore it
log.error("optimizeParseNode error", e);
}
return SemanticNode.getSql(parserNode, engineType); return SemanticNode.getSql(parserNode, engineType);
} }

View File

@@ -315,11 +315,11 @@ public class CalciteSqlParserTest {
+ " \"updatedBy\": \"admin\",\n" + " \"updatedBy\": \"admin\",\n"
+ " \"createdAt\": 1711367511146,\n" + " \"createdAt\": 1711367511146,\n"
+ " \"updatedAt\": 1711367511146\n" + " }\n" + " }\n" + "}"; + " \"updatedAt\": 1711367511146\n" + " }\n" + " }\n" + "}";
QueryStatement queryStatement = JSON.parseObject(json, QueryStatement.class); // QueryStatement queryStatement = JSON.parseObject(json, QueryStatement.class);
OntologyQueryParser calciteSqlParser = new OntologyQueryParser(); // OntologyQueryParser calciteSqlParser = new OntologyQueryParser();
calciteSqlParser.parse(queryStatement); // calciteSqlParser.parse(queryStatement);
Assert.assertEquals(queryStatement.getSql().trim().replaceAll("\\s+", ""), // Assert.assertEquals(queryStatement.getSql().trim().replaceAll("\\s+", ""),
"SELECT`imp_date`AS`sys_imp_date`,SUM(1)AS`pv`" + "FROM" + "`s2_pv_uv_statis`" // "SELECT`imp_date`AS`sys_imp_date`,SUM(1)AS`pv`" + "FROM" + "`s2_pv_uv_statis`"
+ "GROUPBY`imp_date`,`imp_date`"); // + "GROUPBY`imp_date`,`imp_date`");
} }
} }

View File

@@ -141,7 +141,7 @@ public class DimValueAspect {
List<String> values = JsonUtil.toList(fieldValue, String.class); List<String> values = JsonUtil.toList(fieldValue, String.class);
List<String> revisedValues = new ArrayList<>(); List<String> revisedValues = new ArrayList<>();
for (int i = 0; i < values.size(); i++) { for (int i = 0; i < values.size(); i++) {
Boolean flag = new Boolean(false); Boolean flag = false;
for (DimValueMap dimValueMap : dimension.getDimValueMaps()) { for (DimValueMap dimValueMap : dimension.getDimValueMaps()) {
if (!CollectionUtils.isEmpty(dimValueMap.getAlias()) if (!CollectionUtils.isEmpty(dimValueMap.getAlias())
&& dimValueMap.getAlias().contains(values.get(i))) { && dimValueMap.getAlias().contains(values.get(i))) {

View File

@@ -24,7 +24,7 @@ public interface SemanticLayerService {
DataSetSchema getDataSetSchema(Long id); DataSetSchema getDataSetSchema(Long id);
List<ItemResp> getDomainDataSetTree(); List<ItemResp> getDomainDataSetTree(User user);
List<DimensionResp> getDimensions(MetaFilter metaFilter); List<DimensionResp> getDimensions(MetaFilter metaFilter);

View File

@@ -5,6 +5,7 @@ import com.google.common.collect.Sets;
import com.tencent.supersonic.common.pojo.Constants; import com.tencent.supersonic.common.pojo.Constants;
import com.tencent.supersonic.common.pojo.QueryColumn; import com.tencent.supersonic.common.pojo.QueryColumn;
import com.tencent.supersonic.common.pojo.User; import com.tencent.supersonic.common.pojo.User;
import com.tencent.supersonic.common.pojo.enums.AuthType;
import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum; import com.tencent.supersonic.common.pojo.enums.TaskStatusEnum;
import com.tencent.supersonic.headless.api.pojo.DataSetSchema; import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
import com.tencent.supersonic.headless.api.pojo.Dimension; import com.tencent.supersonic.headless.api.pojo.Dimension;
@@ -29,10 +30,7 @@ import com.tencent.supersonic.headless.core.utils.ComponentFactory;
import com.tencent.supersonic.headless.server.annotation.S2DataPermission; import com.tencent.supersonic.headless.server.annotation.S2DataPermission;
import com.tencent.supersonic.headless.server.facade.service.SemanticLayerService; import com.tencent.supersonic.headless.server.facade.service.SemanticLayerService;
import com.tencent.supersonic.headless.server.manager.SemanticSchemaManager; import com.tencent.supersonic.headless.server.manager.SemanticSchemaManager;
import com.tencent.supersonic.headless.server.service.DataSetService; import com.tencent.supersonic.headless.server.service.*;
import com.tencent.supersonic.headless.server.service.DimensionService;
import com.tencent.supersonic.headless.server.service.MetricService;
import com.tencent.supersonic.headless.server.service.SchemaService;
import com.tencent.supersonic.headless.server.utils.MetricDrillDownChecker; import com.tencent.supersonic.headless.server.utils.MetricDrillDownChecker;
import com.tencent.supersonic.headless.server.utils.QueryUtils; import com.tencent.supersonic.headless.server.utils.QueryUtils;
import com.tencent.supersonic.headless.server.utils.StatUtils; import com.tencent.supersonic.headless.server.utils.StatUtils;
@@ -59,6 +57,7 @@ public class S2SemanticLayerService implements SemanticLayerService {
private final MetricDrillDownChecker metricDrillDownChecker; private final MetricDrillDownChecker metricDrillDownChecker;
private final KnowledgeBaseService knowledgeBaseService; private final KnowledgeBaseService knowledgeBaseService;
private final MetricService metricService; private final MetricService metricService;
private final DomainService domainService;
private final DimensionService dimensionService; private final DimensionService dimensionService;
private final TranslatorConfig translatorConfig; private final TranslatorConfig translatorConfig;
private final QueryCache queryCache = ComponentFactory.getQueryCache(); private final QueryCache queryCache = ComponentFactory.getQueryCache();
@@ -69,7 +68,8 @@ public class S2SemanticLayerService implements SemanticLayerService {
SchemaService schemaService, SemanticTranslator semanticTranslator, SchemaService schemaService, SemanticTranslator semanticTranslator,
MetricDrillDownChecker metricDrillDownChecker, MetricDrillDownChecker metricDrillDownChecker,
KnowledgeBaseService knowledgeBaseService, MetricService metricService, KnowledgeBaseService knowledgeBaseService, MetricService metricService,
DimensionService dimensionService, TranslatorConfig translatorConfig) { DimensionService dimensionService, DomainService domainService,
TranslatorConfig translatorConfig) {
this.statUtils = statUtils; this.statUtils = statUtils;
this.queryUtils = queryUtils; this.queryUtils = queryUtils;
this.semanticSchemaManager = semanticSchemaManager; this.semanticSchemaManager = semanticSchemaManager;
@@ -80,6 +80,7 @@ public class S2SemanticLayerService implements SemanticLayerService {
this.knowledgeBaseService = knowledgeBaseService; this.knowledgeBaseService = knowledgeBaseService;
this.metricService = metricService; this.metricService = metricService;
this.dimensionService = dimensionService; this.dimensionService = dimensionService;
this.domainService = domainService;
this.translatorConfig = translatorConfig; this.translatorConfig = translatorConfig;
} }
@@ -262,8 +263,11 @@ public class S2SemanticLayerService implements SemanticLayerService {
} }
@Override @Override
public List<ItemResp> getDomainDataSetTree() { public List<ItemResp> getDomainDataSetTree(User user) {
return schemaService.getDomainDataSetTree(); List<Long> domainsWithAuth = domainService.getDomainAuthSet(user, AuthType.VIEWER).stream()
.map(DomainResp::getId).toList();
return schemaService.getDomainDataSetTree().stream()
.filter(item -> domainsWithAuth.contains(item.getId())).toList();
} }
@Override @Override

View File

@@ -36,6 +36,7 @@ public class ModelYamlManager {
} else { } else {
dataModelYamlTpl.setTableQuery(modelDetail.getTableQuery()); dataModelYamlTpl.setTableQuery(modelDetail.getTableQuery());
} }
dataModelYamlTpl.setFilterSql(modelDetail.getFilterSql());
dataModelYamlTpl.setFields(modelResp.getModelDetail().getFields()); dataModelYamlTpl.setFields(modelResp.getModelDetail().getFields());
dataModelYamlTpl.setId(modelResp.getId()); dataModelYamlTpl.setId(modelResp.getId());
return dataModelYamlTpl; return dataModelYamlTpl;

View File

@@ -97,9 +97,11 @@ public class SemanticSchemaManager {
modelDetail.setDbType(d.getType()); modelDetail.setDbType(d.getType());
modelDetail.setSqlQuery(d.getSqlQuery()); modelDetail.setSqlQuery(d.getSqlQuery());
modelDetail.setTableQuery(d.getTableQuery()); modelDetail.setTableQuery(d.getTableQuery());
modelDetail.setFilterSql(d.getFilterSql());
modelDetail.getIdentifiers().addAll(getIdentify(d.getIdentifiers())); modelDetail.getIdentifiers().addAll(getIdentify(d.getIdentifiers()));
modelDetail.getMeasures().addAll(getMeasureParams(d.getMeasures())); modelDetail.getMeasures().addAll(getMeasureParams(d.getMeasures()));
modelDetail.getDimensions().addAll(getDimensions(d.getDimensions())); modelDetail.getDimensions().addAll(getDimensions(d.getDimensions()));
modelDetail.getFields().addAll(d.getFields());
return dataModel; return dataModel;
} }

View File

@@ -75,6 +75,7 @@ public class LLMSemanticModeller implements SemanticModeller {
if (!chatApp.isPresent() || !chatApp.get().isEnable()) { if (!chatApp.isPresent() || !chatApp.get().isEnable()) {
return; return;
} }
List<DbSchema> otherDbSchema = getOtherDbSchema(dbSchema, dbSchemas); List<DbSchema> otherDbSchema = getOtherDbSchema(dbSchema, dbSchemas);
ModelSchemaExtractor extractor = ModelSchemaExtractor extractor =
AiServices.create(ModelSchemaExtractor.class, getChatModel(modelBuildReq)); AiServices.create(ModelSchemaExtractor.class, getChatModel(modelBuildReq));

View File

@@ -1,9 +1,9 @@
package com.tencent.supersonic.headless.server.modeller; package com.tencent.supersonic.headless.server.modeller;
import com.tencent.supersonic.headless.api.pojo.ColumnSchema;
import com.tencent.supersonic.headless.api.pojo.DBColumn; import com.tencent.supersonic.headless.api.pojo.DBColumn;
import com.tencent.supersonic.headless.api.pojo.DbSchema; import com.tencent.supersonic.headless.api.pojo.DbSchema;
import com.tencent.supersonic.headless.api.pojo.ModelSchema; import com.tencent.supersonic.headless.api.pojo.ModelSchema;
import com.tencent.supersonic.headless.api.pojo.SemanticColumn;
import com.tencent.supersonic.headless.api.pojo.request.ModelBuildReq; import com.tencent.supersonic.headless.api.pojo.request.ModelBuildReq;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -16,19 +16,20 @@ public class RuleSemanticModeller implements SemanticModeller {
@Override @Override
public void build(DbSchema dbSchema, List<DbSchema> dbSchemas, ModelSchema modelSchema, public void build(DbSchema dbSchema, List<DbSchema> dbSchemas, ModelSchema modelSchema,
ModelBuildReq modelBuildReq) { ModelBuildReq modelBuildReq) {
List<ColumnSchema> columnSchemas = List<SemanticColumn> semanticColumns =
dbSchema.getDbColumns().stream().map(this::convert).collect(Collectors.toList()); dbSchema.getDbColumns().stream().map(this::convert).collect(Collectors.toList());
modelSchema.setColumnSchemas(columnSchemas); modelSchema.setSemanticColumns(semanticColumns);
} }
private ColumnSchema convert(DBColumn dbColumn) { private SemanticColumn convert(DBColumn dbColumn) {
ColumnSchema columnSchema = new ColumnSchema(); SemanticColumn semanticColumn = new SemanticColumn();
columnSchema.setName(dbColumn.getColumnName()); semanticColumn.setName(dbColumn.getColumnName());
columnSchema.setColumnName(dbColumn.getColumnName()); semanticColumn.setColumnName(dbColumn.getColumnName());
columnSchema.setComment(dbColumn.getComment()); semanticColumn.setExpr(dbColumn.getColumnName());
columnSchema.setDataType(dbColumn.getDataType()); semanticColumn.setComment(dbColumn.getComment());
columnSchema.setFiledType(dbColumn.getFieldType()); semanticColumn.setDataType(dbColumn.getDataType());
return columnSchema; semanticColumn.setFiledType(dbColumn.getFieldType());
return semanticColumn;
} }
} }

View File

@@ -7,6 +7,9 @@ import com.tencent.supersonic.headless.api.pojo.request.ModelBuildReq;
import java.util.List; import java.util.List;
/**
* A semantic modeler builds semantic-layer schemas from database-layer schemas.
*/
public interface SemanticModeller { public interface SemanticModeller {
void build(DbSchema dbSchema, List<DbSchema> otherDbSchema, ModelSchema modelSchema, void build(DbSchema dbSchema, List<DbSchema> otherDbSchema, ModelSchema modelSchema,

View File

@@ -44,6 +44,8 @@ public class DatabaseDO {
/** */ /** */
private String viewer; private String viewer;
private Integer isOpen = 0;
/** 配置信息 */ /** 配置信息 */
private String config; private String config;

View File

@@ -21,6 +21,8 @@ public class DataModelYamlTpl {
private String tableQuery; private String tableQuery;
private String filterSql;
private List<IdentifyYamlTpl> identifiers; private List<IdentifyYamlTpl> identifiers;
private List<DimensionYamlTpl> dimensions; private List<DimensionYamlTpl> dimensions;

Some files were not shown because too many files have changed in this diff Show More