mirror of
https://github.com/tencentmusic/supersonic.git
synced 2026-04-20 13:44:19 +08:00
Compare commits
2 Commits
v0.9.10
...
48985f5a61
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48985f5a61 | ||
|
|
5b45cfbad7 |
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
69
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -11,28 +11,59 @@ body:
|
||||
If it is an idea or help wanted, please go to:
|
||||
[Github Discussion](https://github.com/tencentmusic/supersonic/discussions)
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: SuperSonic version
|
||||
description: Please tell us which version you are using.
|
||||
placeholder: "0.9.8"
|
||||
validations:
|
||||
required: true
|
||||
label: Search before asking
|
||||
description: >
|
||||
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
||||
whether the same issue was reported already.
|
||||
options:
|
||||
- label: >
|
||||
I had searched in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) and found no similar
|
||||
issues.
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: organization
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Your organization
|
||||
description: Please tell us your organization so that we can provide you better support and advice.
|
||||
placeholder: "TME..."
|
||||
label: Version
|
||||
description: What is the current version
|
||||
placeholder: >
|
||||
Please provide the version you are using.
|
||||
If it is the trunk version, please input commit id.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Describe the bug you met.
|
||||
label: What's Wrong?
|
||||
description: Describe the bug.
|
||||
placeholder: >
|
||||
Describe the specific problem, the more detailed the better.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What You Expected?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How to Reproduce?
|
||||
placeholder: >
|
||||
Please try to give reproducing steps to facilitate quick location of the problem.
|
||||
|
||||
- What actions were performed
|
||||
- Table building statement
|
||||
- Import statement
|
||||
- Cluster information: number of nodes, configuration, etc.
|
||||
|
||||
If it is hard to reproduce, please also explain the general scene.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything Else?
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
@@ -43,6 +74,16 @@ body:
|
||||
options:
|
||||
- label: Yes I am willing to submit a PR!
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
|
||||
options:
|
||||
- label: >
|
||||
I agree to follow this project's
|
||||
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thanks for completing our form!"
|
||||
|
||||
34
.github/ISSUE_TEMPLATE/enhancement_request.yml
vendored
34
.github/ISSUE_TEMPLATE/enhancement_request.yml
vendored
@@ -8,20 +8,30 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
Thank you very much for your good enhancement for SuperSonic.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Search before asking
|
||||
description: >
|
||||
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
||||
whether the same issue was reported already.
|
||||
options:
|
||||
- label: >
|
||||
I had searched in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) and found no similar
|
||||
issues.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Describe the enhancement what you want, including motivation if it exists.
|
||||
|
||||
- type: input
|
||||
id: organization
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Your organization
|
||||
description: Please tell us your organization so that we can provide you better support and advice.
|
||||
placeholder: "TME..."
|
||||
validations:
|
||||
required: true
|
||||
label: Solution
|
||||
placeholder: >
|
||||
Add overview of proposed solution.
|
||||
|
||||
Add related materials like links if they exist.
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
@@ -32,6 +42,16 @@ body:
|
||||
options:
|
||||
- label: Yes I am willing to submit a PR!
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
|
||||
options:
|
||||
- label: >
|
||||
I agree to follow this project's
|
||||
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thanks for completing our form!"
|
||||
|
||||
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
40
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -8,19 +8,33 @@ body:
|
||||
value: |
|
||||
Thank you very much for your good ideas and suggestions for SuperSonic
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Search before asking
|
||||
description: >
|
||||
Please make sure to search in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) first to see
|
||||
whether the same issue was reported already.
|
||||
options:
|
||||
- label: >
|
||||
I had searched in the [issues](https://github.com/tencentmusic/supersonic/issues?q=is%3Aissue) and found no similar
|
||||
issues.
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Describe your ideas and needs.
|
||||
|
||||
- type: input
|
||||
id: organization
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Your organization
|
||||
description: Please tell us your organization so that we can provide you better support and advice.
|
||||
placeholder: "TME..."
|
||||
validations:
|
||||
required: true
|
||||
label: Use case
|
||||
placeholder: >
|
||||
What problem does this feature mainly solve, or what scenarios it is suitable for.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Related issues
|
||||
description: Is there currently another issue associated with this?
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
@@ -31,4 +45,16 @@ body:
|
||||
options:
|
||||
- label: Yes I am willing to submit a PR!
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
|
||||
options:
|
||||
- label: >
|
||||
I agree to follow this project's
|
||||
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thanks for completing our form!"
|
||||
|
||||
46
.github/ISSUE_TEMPLATE/question_request.yml
vendored
46
.github/ISSUE_TEMPLATE/question_request.yml
vendored
@@ -8,7 +8,6 @@ body:
|
||||
value: |
|
||||
## Ask a Question about SuperSonic
|
||||
Please provide a detailed description of your question or the clarification you seek regarding the SuperSonic project.
|
||||
|
||||
- type: textarea
|
||||
id: describe-question
|
||||
attributes:
|
||||
@@ -17,12 +16,43 @@ body:
|
||||
placeholder: "Type your question here..."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: organization
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Your organization
|
||||
description: Please tell us your organization so that we can provide you better support and advice.
|
||||
placeholder: "TME..."
|
||||
label: Provide any additional context or information
|
||||
description: If your question is related to a specific part of the SuperSonic project or if you have already looked through certain documentation, please provide that information here.
|
||||
placeholder: "Add context here..."
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
- type: textarea
|
||||
id: tried-to-resolve
|
||||
attributes:
|
||||
label: What have you tried to resolve your question
|
||||
description: Let us know what you have done to try and understand or resolve your question. This can help us provide you with the most useful guidance.
|
||||
placeholder: "I've already tried..."
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Your environment
|
||||
description: Share details about your environment to help us reproduce the issue. Include your operating system, version of SuperSonic, and any other relevant details.
|
||||
placeholder: "OS, SuperSonic version, etc..."
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: screenshots-logs
|
||||
attributes:
|
||||
label: Screenshots or Logs
|
||||
description: If applicable, add screenshots or logs to help explain your problem.
|
||||
placeholder: "Paste your logs or attach screenshots here..."
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Add any other context or details you think might be helpful for understanding your question.
|
||||
placeholder: "Any other information..."
|
||||
validations:
|
||||
required: false
|
||||
6
.github/workflows/docker-publish.yml
vendored
6
.github/workflows/docker-publish.yml
vendored
@@ -28,5 +28,7 @@ jobs:
|
||||
- name: Build and publish Docker image
|
||||
run: |
|
||||
VERSION=${{ github.event.inputs.version }}
|
||||
chmod +x docker/docker-build-publish.sh
|
||||
sh docker/docker-build-publish.sh $VERSION
|
||||
chmod +x docker/docker-build.sh
|
||||
chmod +x docker/docker-publish.sh
|
||||
sh docker/docker-build.sh $VERSION
|
||||
sh docker/docker-publish.sh $VERSION
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,5 +19,4 @@ assembly/runtime/*
|
||||
chm_db/
|
||||
__pycache__/
|
||||
/dict
|
||||
assembly/build/*-SNAPSHOT
|
||||
**/node_modules/
|
||||
assembly/build/*-SNAPSHOT
|
||||
490
LICENSE
490
LICENSE
@@ -1,41 +1,489 @@
|
||||
Apache License Version 2.0
|
||||
SuperSonic is licensed under the MIT License, with the following additional conditions:
|
||||
|
||||
Copyright (2025) The SuperSonic Project Authors. All rights reserved.
|
||||
1. You may provide SuperSonic to third parties as a commercial software or service. However,
|
||||
when the following conditions are met, you must contact the producer to obtain a commercial license:
|
||||
|
||||
----------
|
||||
|
||||
SuperSonic is licensed under the Apache License 2.0, with the following additional conditions:
|
||||
|
||||
1. The commercial usage of SuperSonic:
|
||||
|
||||
a. SuperSonic may be utilized commercially, including as a frontend and backend service without modifying the source
|
||||
code and logo.
|
||||
|
||||
b. a commercial license must be obtained from the author if you want to develop and distribute a derivative work based
|
||||
on SuperSonic.
|
||||
|
||||
Please contact zhangjun2915@163.com by email to inquire about licensing matters.
|
||||
a. Multi-tenant SaaS service: Unless explicitly authorized by SuperSonic in writing, you may not use the
|
||||
SuperSonic source code to operate a multi-tenant SaaS service.
|
||||
b. LOGO and copyright information: In the process of using SuperSonic, you may not remove or modify
|
||||
the LOGO or copyright information on the SuperSonic UI. This restriction is inapplicable to uses of
|
||||
SuperSonic that do not involve its frontend components.
|
||||
|
||||
Please contact jerryjzhang@tencent.com by email to inquire about licensing matters.
|
||||
|
||||
2. As a contributor, you should agree that:
|
||||
|
||||
a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
|
||||
b. Your contributed code may be used for commercial purposes, including but not limited to its business operations.
|
||||
|
||||
b. Your contributed code may be used for commercial purposes, including but not limited to its cloud edition.
|
||||
Terms of the MIT License:
|
||||
--------------------------------------------------------------------
|
||||
MIT License
|
||||
|
||||
Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0.
|
||||
Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
|
||||
Copyright (c) 2023 Tencent Music Entertainment
|
||||
|
||||
----------
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
|
||||
Open Source Software Licensed under the MIT License:
|
||||
--------------------------------------------------------------------
|
||||
1. Mybatis-PageHelper 1.2.10
|
||||
Copyright (c) 2014-2022 abel533@gmail.com
|
||||
|
||||
2. lombok
|
||||
Copyright (C) 2009-2021 The Project Lombok Authors.
|
||||
|
||||
3. react
|
||||
Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
||||
4. ant-design
|
||||
Copyright (c) 2015-present Ant UED, https://xtech.antfin.com/
|
||||
|
||||
5. ant-design-pro
|
||||
Copyright (c) 2019 Alipay.inc
|
||||
|
||||
6. @ant-design/charts
|
||||
Copyright (c) 2021 Ant Design
|
||||
|
||||
7. @ant-design/icons
|
||||
Copyright (c) 2018-present Ant UED, https://xtech.antfin.com/
|
||||
|
||||
8. @antv/layout
|
||||
Copyright (c) 2018 Alipay.inc
|
||||
|
||||
9. @antv/xflow
|
||||
Copyright (c) 2021-2023 Alipay.inc
|
||||
|
||||
10. umi
|
||||
Copyright (c) 2017-present ChenCheng (sorrycc@gmail.com)
|
||||
|
||||
11. @umijs/route-utils
|
||||
Copyright (c) 2019-present chenshuai2144 (qixian.cs@outlook.com)
|
||||
|
||||
12. ahooks
|
||||
Copyright (c) 2020 ahooks
|
||||
|
||||
13. axios
|
||||
Copyright (c) 2014-present Matt Zabriskie & Collaborators
|
||||
|
||||
14. classnames
|
||||
Copyright (c) 2018 Jed Watson
|
||||
|
||||
15. crypto-js
|
||||
Copyright (c) 2009-2013 Jeff Mott
|
||||
Copyright (c) 2013-2016 Evan Vosberg
|
||||
|
||||
16. immutability-helper
|
||||
Copyright (c) 2017 Moshe Kolodny
|
||||
|
||||
17. lodash
|
||||
Copyright JS Foundation and other contributors <https://js.foundation/>
|
||||
|
||||
18. moment
|
||||
Copyright (c) JS Foundation and other contributors
|
||||
|
||||
19. numeral
|
||||
Copyright (c) 2016 Adam Draper
|
||||
|
||||
20. omit.js
|
||||
Copyright (c) 2016 Benjy Cui
|
||||
|
||||
21. rc-menu
|
||||
Copyright (c) 2014-present yiminghe
|
||||
|
||||
22. rc-util
|
||||
Copyright (c) 2014-present yiminghe
|
||||
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
|
||||
|
||||
23. react-ace
|
||||
Copyright (c) 2014 James Hrisho
|
||||
|
||||
24. react-dev-inspector
|
||||
Copyright (c) zthxxx (https://blog.zthxxx.me)
|
||||
|
||||
25. react-lazyload
|
||||
Copyright (c) 2015 Sen Yang
|
||||
|
||||
26. react-spinners
|
||||
Copyright (c) 2017 David Hu
|
||||
|
||||
27.react-split-pane
|
||||
Copyright (c) 2015 tomkp
|
||||
|
||||
28. snappyjs
|
||||
Copyright (c) 2016 Zhipeng Jia
|
||||
|
||||
29. sql-formatter
|
||||
Copyright (c) 2016-2020 ZeroTurnaround LLC
|
||||
Copyright (c) 2020-2021 George Leslie-Waksman and other contributors
|
||||
Copyright (c) 2021-Present inferrinizzard and other contributors
|
||||
|
||||
30. @ant-design/pro-cli
|
||||
Copyright (c) 2017-2018 Alipay
|
||||
|
||||
31. cross-env
|
||||
Copyright (c) 2017 Kent C. Dodds
|
||||
|
||||
32.cross-port-killer
|
||||
Copyright (c) 2017 Rafael Milewski
|
||||
|
||||
33.detect-installer
|
||||
Copyright (c) 2019-present chenshuai2144 (qixian.cs@outlook.com)
|
||||
|
||||
34.eslint
|
||||
Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
||||
|
||||
35.express
|
||||
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
|
||||
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||
|
||||
36.gh-pages
|
||||
Copyright (c) 2014 Tim Schaub
|
||||
|
||||
37.inflect
|
||||
Copyright (C) 2020 Pavan Kumar Sunkara
|
||||
|
||||
38.lint-staged
|
||||
Copyright (c) 2016 Andrey Okonetchnikov
|
||||
|
||||
39.prettier
|
||||
Copyright © James Long and contributors
|
||||
|
||||
40.stylelint
|
||||
Copyright (c) 2015 - present Maxime Thirouin, David Clark & Richard Hallows
|
||||
|
||||
41.umi-serve
|
||||
Copyright (c) 2017-present ChenCheng (sorrycc@gmail.com)
|
||||
|
||||
42.webpack
|
||||
Copyright JS Foundation and other contributors
|
||||
|
||||
43.react-dnd
|
||||
Copyright (c) 2015 Dan Abramov
|
||||
|
||||
44.react-grid-layout
|
||||
Copyright (c) 2016 Samuel Reed
|
||||
|
||||
45.slat
|
||||
Copyright © 2016–2023, Ian Storm Taylor
|
||||
|
||||
46.html2canvas
|
||||
Copyright (c) 2012 Niklas von Hertzen
|
||||
|
||||
47.core-js
|
||||
Copyright (c) 2014-2020 Denis Pushkarev
|
||||
|
||||
48.immer 4.0.2
|
||||
Copyright (c) 2017 Michel Weststrate
|
||||
|
||||
49.redux
|
||||
Copyright (c) 2015-present Dan Abramov
|
||||
The Redux logo is dedicated to the public domain and licensed under CC0.
|
||||
|
||||
50.redux-saga
|
||||
Copyright (c) 2015 Yassine Elouafi
|
||||
The Redux-Saga logo is dedicated to the public domain and licensed under CC0.
|
||||
|
||||
51.ts-loader
|
||||
Copyright (c) 2015 TypeStrong
|
||||
|
||||
52.minimist
|
||||
Files:https://github.com/minimistjs/minimist/tree/v1.2.3
|
||||
License Details:https://github.com/minimistjs/minimist/blob/main/LICENSE
|
||||
|
||||
53.intl
|
||||
copyright (c) 2013 Andy Earnshaw
|
||||
|
||||
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
|
||||
Open Source Software Licensed under the Apache License Version 2.0:
|
||||
--------------------------------------------------------------------
|
||||
1. HanLP
|
||||
Files: https://github.com/hankcs/HanLP/tree/v1.8.3
|
||||
License Details: https://github.com/hankcs/HanLP/blob/v1.8.3/LICENSE
|
||||
|
||||
2. mybatis
|
||||
iBATIS
|
||||
This product includes software developed by
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
Copyright 2010 The Apache Software Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
3. guava
|
||||
Files: https://github.com/google/guava/tree/v20.0
|
||||
License Details: https://github.com/google/guava/blob/master/LICENSE
|
||||
|
||||
4. hadoop
|
||||
This product includes software developed by The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
5. Jackson
|
||||
Files: https://github.com/FasterXML/jackson-core/tree/2.11
|
||||
License Details: https://github.com/FasterXML/jackson-core/blob/2.11/LICENSE
|
||||
|
||||
6. commons-lang
|
||||
Apache Commons Lang
|
||||
Copyright 2001-2017 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
This product includes software from the Spring Framework,
|
||||
under the Apache License 2.0 (see: StringUtils.containsWhitespace())
|
||||
|
||||
7. testng
|
||||
Files:https://github.com/testng-team/testng/tree/6.13.1
|
||||
License Details:https://github.com/testng-team/testng/blob/6.13.1/LICENSE.txt
|
||||
|
||||
8. jackson-dataformat-yaml
|
||||
Files:https://github.com/FasterXML/jackson-dataformat-yaml/tree/jackson-dataformat-yaml-2.8.11
|
||||
License Details:https://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
|
||||
9. druid
|
||||
Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
limitations under the License.
|
||||
|
||||
10. davinci
|
||||
Licensed to Apereo under one or more contributor license
|
||||
agreements. See the NOTICE file distributed with this work
|
||||
for additional information regarding copyright ownership.
|
||||
Apereo licenses this file to you under the Apache License,
|
||||
Version 2.0 (the "License"); you may not use this file
|
||||
except in compliance with the License. You may obtain a
|
||||
copy of the License at the following location:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
11. echarts
|
||||
Apache ECharts
|
||||
Copyright 2017-2023 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (https://www.apache.org/).
|
||||
|
||||
12. echarts-wordcloud
|
||||
Apache ECharts
|
||||
Copyright 2017-2023 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (https://www.apache.org/).
|
||||
|
||||
13. carlo
|
||||
Files:https://github.com/GoogleChromeLabs/carlo
|
||||
License Details:https://github.com/GoogleChromeLabs/carlo/blob/master/LICENSE
|
||||
|
||||
14. puppeteer-core
|
||||
Copyright 2017 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
15. swagger-ui-react
|
||||
swagger-ui
|
||||
Copyright 2020-2021 SmartBear Software Inc.
|
||||
|
||||
16. typescript
|
||||
files:https://github.com/microsoft/TypeScript
|
||||
License Details:https://github.com/microsoft/TypeScript/blob/main/LICENSE.txt
|
||||
|
||||
17. io.jsonwebtoken
|
||||
Copyright (C) 2014 jsonwebtoken.io
|
||||
Files: https://repo1.maven.org/maven2/io/jsonwebtoken/jjwt/0.9.1/jjwt-0.9.1.jar
|
||||
|
||||
|
||||
Terms of the Apache License Version 2.0:
|
||||
--------------------------------------------------------------------
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
Open Source Software Licensed under the Modified BSD License:
|
||||
--------------------------------------------------------------------
|
||||
1. node-sha1
|
||||
Copyright © 2009, Jeff Mott. All rights reserved.
|
||||
Copyright © 2011, Paul Vorbach. All rights reserved.
|
||||
|
||||
This project is licensed under the terms of the Modified BSD License, as follows:
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2005-2023, NumPy Developers.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name oCrypto-JS nor the names of any contributors
|
||||
may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
2. ace-builds
|
||||
Copyright (c) 2010, Ajax.org B.V.
|
||||
All rights reserved.
|
||||
|
||||
This project is licensed under the terms of the Modified BSD License, as follows:
|
||||
-------------------------------------------------------------------
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Ajax.org B.V. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Other Open Source Software:
|
||||
--------------------------------------------------------------------
|
||||
1. jsencrypt
|
||||
Files:https://github.com/travist/jsencrypt
|
||||
License Details:https://github.com/travist/jsencrypt/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,15 +35,10 @@ function buildWebapp {
|
||||
chmod +x $projectDir/webapp/start-fe-prod.sh
|
||||
cd $projectDir/webapp
|
||||
sh ./start-fe-prod.sh
|
||||
# check build result
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to build frontend webapp."
|
||||
exit 1
|
||||
fi
|
||||
cp -fr ./supersonic-webapp.tar.gz ${buildDir}/
|
||||
# check build result
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to get supersonic webapp package."
|
||||
echo "Failed to build frontend webapp."
|
||||
exit 1
|
||||
fi
|
||||
echo "finished building supersonic webapp"
|
||||
@@ -61,11 +56,6 @@ function packageRelease {
|
||||
# package webapp
|
||||
tar xvf supersonic-webapp.tar.gz
|
||||
mv supersonic-webapp webapp
|
||||
# check webapp build result
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to get supersonic webapp package."
|
||||
exit 1
|
||||
fi
|
||||
json='{"env": "''"}'
|
||||
echo $json > webapp/supersonic.config.json
|
||||
mv webapp $release_dir/
|
||||
|
||||
@@ -4,7 +4,6 @@ chcp 65001
|
||||
|
||||
set "sbinDir=%~dp0"
|
||||
call %sbinDir%/supersonic-common.bat %*
|
||||
call %sbinDir%/supersonic-env.bat %*
|
||||
|
||||
set "command=%~1"
|
||||
set "service=%~2"
|
||||
@@ -15,7 +14,7 @@ if "%service%"=="" (
|
||||
)
|
||||
|
||||
if "%profile%"=="" (
|
||||
set "profile=%S2_DB_TYPE%"
|
||||
set "profile=local"
|
||||
)
|
||||
|
||||
set "model_name=%service%"
|
||||
@@ -55,8 +54,7 @@ if "%command%"=="restart" (
|
||||
set "webDir=%baseDir%\webapp"
|
||||
set "logDir=%baseDir%\logs"
|
||||
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 "java-command=%property% -Xms1024m -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%"
|
||||
set "java-command=-Dfile.encoding=UTF-8 -Duser.language=Zh -Duser.region=CN -Duser.timezone=GMT+08 -Dspring.profiles.active=%profile% -Xms1024m -Xmx1024m -cp %CLASSPATH% %MAIN_CLASS%"
|
||||
if not exist %logDir% mkdir %logDir%
|
||||
start /B java %java-command% >nul 2>&1
|
||||
timeout /t 10 >nul
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
sbinDir=$(cd "$(dirname "$0")"; pwd)
|
||||
source $sbinDir/supersonic-common.sh
|
||||
source $sbinDir/supersonic-env.sh
|
||||
|
||||
command=$1
|
||||
service=$2
|
||||
@@ -13,7 +12,7 @@ if [ -z "$service" ]; then
|
||||
fi
|
||||
|
||||
if [ -z "$profile" ]; then
|
||||
profile=${S2_DB_TYPE}
|
||||
profile="local"
|
||||
fi
|
||||
|
||||
model_name=$service
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
:: Set below DB configs to connect to your own database
|
||||
:: Supported DB_TYPE: h2, mysql, postgres
|
||||
set "S2_DB_TYPE=h2"
|
||||
set "S2_DB_HOST="
|
||||
set "S2_DB_PORT="
|
||||
set "S2_DB_USER="
|
||||
set "S2_DB_PASSWORD="
|
||||
set "S2_DB_DATABASE="
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#### 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=
|
||||
@@ -12,7 +12,4 @@ public class UserReq {
|
||||
|
||||
@NotBlank(message = "password can not be null")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "password can not be null")
|
||||
private String newPassword;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
package com.tencent.supersonic.auth.authentication.interceptor;
|
||||
|
||||
import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfig;
|
||||
import com.tencent.supersonic.auth.api.authentication.constant.UserConstants;
|
||||
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl;
|
||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||
import com.tencent.supersonic.common.util.S2ThreadContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.connector.RequestFacade;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.tomcat.util.http.MimeHeaders;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -20,6 +27,8 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
|
||||
|
||||
protected TokenService tokenService;
|
||||
|
||||
protected S2ThreadContext s2ThreadContext;
|
||||
|
||||
protected boolean isExcludedUri(String uri) {
|
||||
String excludePathStr = authenticationConfig.getExcludePath();
|
||||
if (StringUtils.isEmpty(excludePathStr)) {
|
||||
@@ -44,4 +53,52 @@ public abstract class AuthenticationInterceptor implements HandlerInterceptor {
|
||||
return includePaths.stream().anyMatch(uri::startsWith);
|
||||
}
|
||||
|
||||
protected boolean isInternalRequest(HttpServletRequest request) {
|
||||
String internal = request.getHeader(UserConstants.INTERNAL);
|
||||
return "true".equalsIgnoreCase(internal);
|
||||
}
|
||||
|
||||
protected boolean isAppRequest(HttpServletRequest request) {
|
||||
String appId = request.getHeader(authenticationConfig.getAppId());
|
||||
return StringUtils.isNotBlank(appId);
|
||||
}
|
||||
|
||||
protected void reflectSetParam(HttpServletRequest request, String key, String value) {
|
||||
try {
|
||||
if (request instanceof StandardMultipartHttpServletRequest) {
|
||||
RequestFacade servletRequest =
|
||||
(RequestFacade) ((StandardMultipartHttpServletRequest) request)
|
||||
.getRequest();
|
||||
Class<? extends HttpServletRequest> servletRequestClazz = servletRequest.getClass();
|
||||
Field request1 = servletRequestClazz.getDeclaredField("request");
|
||||
request1.setAccessible(true);
|
||||
Object o = request1.get(servletRequest);
|
||||
Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
|
||||
coyoteRequest.setAccessible(true);
|
||||
Object o1 = coyoteRequest.get(o);
|
||||
Field headers = o1.getClass().getDeclaredField("headers");
|
||||
headers.setAccessible(true);
|
||||
MimeHeaders o2 = (MimeHeaders) headers.get(o1);
|
||||
if (o2.getValue(key) != null) {
|
||||
o2.setValue(key).setString(value);
|
||||
} else {
|
||||
o2.addValue(key).setString(value);
|
||||
}
|
||||
} else {
|
||||
Class<? extends HttpServletRequest> requestClass = request.getClass();
|
||||
Field request1 = requestClass.getDeclaredField("request");
|
||||
request1.setAccessible(true);
|
||||
Object o = request1.get(request);
|
||||
Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
|
||||
coyoteRequest.setAccessible(true);
|
||||
Object o1 = coyoteRequest.get(o);
|
||||
Field headers = o1.getClass().getDeclaredField("headers");
|
||||
headers.setAccessible(true);
|
||||
MimeHeaders o2 = (MimeHeaders) headers.get(o1);
|
||||
o2.addValue(key).setString(value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("reflectSetParam error:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ import com.tencent.supersonic.auth.api.authentication.config.AuthenticationConfi
|
||||
import com.tencent.supersonic.auth.api.authentication.pojo.UserWithPassword;
|
||||
import com.tencent.supersonic.auth.authentication.service.UserServiceImpl;
|
||||
import com.tencent.supersonic.auth.authentication.utils.TokenService;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import com.tencent.supersonic.common.pojo.exception.AccessException;
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import com.tencent.supersonic.common.util.S2ThreadContext;
|
||||
import com.tencent.supersonic.common.util.ThreadContext;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -32,10 +35,19 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
|
||||
authenticationConfig = ContextUtils.getBean(AuthenticationConfig.class);
|
||||
userServiceImpl = ContextUtils.getBean(UserServiceImpl.class);
|
||||
tokenService = ContextUtils.getBean(TokenService.class);
|
||||
s2ThreadContext = ContextUtils.getBean(S2ThreadContext.class);
|
||||
if (!authenticationConfig.isEnabled()) {
|
||||
setFakerUser(request);
|
||||
return true;
|
||||
}
|
||||
if (isInternalRequest(request)) {
|
||||
setFakerUser(request);
|
||||
return true;
|
||||
}
|
||||
if (isAppRequest(request)) {
|
||||
setFakerUser(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handler instanceof HandlerMethod) {
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
Method method = handlerMethod.getMethod();
|
||||
@@ -56,11 +68,35 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
|
||||
|
||||
UserWithPassword user = getUserWithPassword(request);
|
||||
if (user != null) {
|
||||
setContext(user.getName(), request);
|
||||
return true;
|
||||
}
|
||||
throw new AccessException("authentication failed, please login");
|
||||
}
|
||||
|
||||
private void setFakerUser(HttpServletRequest request) {
|
||||
String token = generateAdminToken(request);
|
||||
reflectSetParam(request, authenticationConfig.getTokenHttpHeaderKey(), token);
|
||||
setContext(User.getDefaultUser().getName(), request);
|
||||
}
|
||||
|
||||
private void setContext(String userName, HttpServletRequest request) {
|
||||
ThreadContext threadContext = ThreadContext.builder()
|
||||
.token(request.getHeader(authenticationConfig.getTokenHttpHeaderKey()))
|
||||
.userName(userName).build();
|
||||
s2ThreadContext.set(threadContext);
|
||||
}
|
||||
|
||||
public String generateAdminToken(HttpServletRequest request) {
|
||||
UserWithPassword admin = new UserWithPassword("admin");
|
||||
admin.setId(1L);
|
||||
admin.setName("admin");
|
||||
admin.setPassword("c3VwZXJzb25pY0BiaWNvbdktJJYWw6A3rEmBUPzbn/6DNeYnD+y3mAwDKEMS3KVT");
|
||||
admin.setDisplayName("admin");
|
||||
admin.setIsAdmin(1);
|
||||
return tokenService.generateToken(UserWithPassword.convert(admin), request);
|
||||
}
|
||||
|
||||
public UserWithPassword getUserWithPassword(HttpServletRequest request) {
|
||||
final Optional<Claims> claimsOptional = tokenService.getClaims(request);
|
||||
if (!claimsOptional.isPresent()) {
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
package com.tencent.supersonic.auth.authentication.persistence.dataobject;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
@TableName("s2_user")
|
||||
public class UserDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
/** */
|
||||
private Long id;
|
||||
|
||||
/** */
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.tencent.supersonic.auth.authentication.persistence.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO;
|
||||
import com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDOExample;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@@ -9,8 +7,12 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface UserDOMapper extends BaseMapper<UserDO> {
|
||||
public interface UserDOMapper {
|
||||
|
||||
/** @mbg.generated */
|
||||
int insert(UserDO record);
|
||||
|
||||
/** @mbg.generated */
|
||||
List<UserDO> selectByExample(UserDOExample example);
|
||||
|
||||
void updateByPrimaryKey(UserDO userDO);
|
||||
|
||||
@@ -72,13 +72,6 @@ public class UserController {
|
||||
return userService.login(userCmd, request);
|
||||
}
|
||||
|
||||
@PostMapping("/resetPassword")
|
||||
public void resetPassword(@RequestBody UserReq userCmd, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
User user = userService.getCurrentUser(request, response);
|
||||
userService.resetPassword(user.getName(), userCmd.getPassword(), userCmd.getNewPassword());
|
||||
}
|
||||
|
||||
@PostMapping("/generateToken")
|
||||
public UserToken generateToken(@RequestBody UserTokenReq userTokenReq,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
@@ -59,6 +59,14 @@
|
||||
limit #{limitStart} , #{limitEnd}
|
||||
</if>
|
||||
</select>
|
||||
<insert id="insert" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
|
||||
insert into s2_user (id, name, password, salt,
|
||||
display_name, email, is_admin
|
||||
)
|
||||
values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR},
|
||||
#{displayName,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{isAdmin,jdbcType=INTEGER}
|
||||
)
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="com.tencent.supersonic.auth.authentication.persistence.dataobject.UserDO">
|
||||
insert into s2_user
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
|
||||
@@ -17,8 +17,6 @@ public class ChatMemoryFilter {
|
||||
|
||||
private Integer agentId;
|
||||
|
||||
private Long queryId;
|
||||
|
||||
private String question;
|
||||
|
||||
private List<String> questions;
|
||||
|
||||
@@ -26,8 +26,4 @@ public class ChatMemoryUpdateReq {
|
||||
private MemoryReviewResult humanReviewRet;
|
||||
|
||||
private String humanReviewCmt;
|
||||
|
||||
private MemoryReviewResult llmReviewRet;
|
||||
|
||||
private String llmReviewCmt;
|
||||
}
|
||||
|
||||
@@ -38,9 +38,6 @@ public class Agent extends RecordInfo {
|
||||
private VisualConfig visualConfig;
|
||||
private List<String> admins = Lists.newArrayList();
|
||||
private List<String> viewers = Lists.newArrayList();
|
||||
private List<String> adminOrgs = Lists.newArrayList();
|
||||
private List<String> viewOrgs = Lists.newArrayList();
|
||||
private Integer isOpen = 0;
|
||||
|
||||
public List<String> getTools(AgentToolType type) {
|
||||
Map<String, Object> map = JSONObject.parseObject(toolConfig, Map.class);
|
||||
@@ -118,8 +115,4 @@ public class Agent extends RecordInfo {
|
||||
return list.apply(this).contains(user.getName());
|
||||
}
|
||||
|
||||
public boolean openToAll() {
|
||||
return isOpen != null && isOpen == 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class SqlExecutor implements ChatQueryExecutor {
|
||||
Text2SQLExemplar.class);
|
||||
|
||||
MemoryService memoryService = ContextUtils.getBean(MemoryService.class);
|
||||
memoryService.createMemory(ChatMemory.builder().queryId(queryResult.getQueryId())
|
||||
memoryService.createMemory(ChatMemory.builder()
|
||||
.agentId(executeContext.getAgent().getId()).status(MemoryStatus.PENDING)
|
||||
.question(exemplar.getQuestion()).sideInfo(exemplar.getSideInfo())
|
||||
.dbSchema(exemplar.getDbSchema()).s2sql(exemplar.getSql())
|
||||
@@ -77,7 +77,6 @@ public class SqlExecutor implements ChatQueryExecutor {
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
QueryResult queryResult = new QueryResult();
|
||||
queryResult.setQueryId(executeContext.getRequest().getQueryId());
|
||||
queryResult.setChatContext(parseInfo);
|
||||
queryResult.setQueryMode(parseInfo.getQueryMode());
|
||||
queryResult.setQueryTimeCost(System.currentTimeMillis() - startTime);
|
||||
|
||||
@@ -3,13 +3,11 @@ package com.tencent.supersonic.chat.server.memory;
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
||||
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||
import com.tencent.supersonic.chat.server.service.AgentService;
|
||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||
import com.tencent.supersonic.common.pojo.ChatApp;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import com.tencent.supersonic.common.pojo.enums.AppModule;
|
||||
import com.tencent.supersonic.common.util.ChatAppManager;
|
||||
import com.tencent.supersonic.headless.server.utils.ModelConfigHelper;
|
||||
@@ -125,10 +123,7 @@ public class MemoryReviewTask {
|
||||
if (MemoryReviewResult.POSITIVE.equals(m.getLlmReviewRet())) {
|
||||
m.setStatus(MemoryStatus.ENABLED);
|
||||
}
|
||||
ChatMemoryUpdateReq memoryUpdateReq = ChatMemoryUpdateReq.builder().id(m.getId())
|
||||
.status(m.getStatus()).llmReviewRet(m.getLlmReviewRet())
|
||||
.llmReviewCmt(m.getLlmReviewCmt()).build();
|
||||
memoryService.updateMemory(memoryUpdateReq, User.getDefaultUser());
|
||||
memoryService.updateMemory(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,12 +100,10 @@ public class NL2SQLParser implements ChatQueryParser {
|
||||
queryNLReq.setMapModeEnum(mode);
|
||||
doParse(queryNLReq, parseResp);
|
||||
}
|
||||
|
||||
if (parseResp.getSelectedParses().isEmpty() && candidateParses.isEmpty()) {
|
||||
if (parseResp.getSelectedParses().isEmpty()) {
|
||||
queryNLReq.setMapModeEnum(MapModeEnum.LOOSE);
|
||||
doParse(queryNLReq, parseResp);
|
||||
}
|
||||
|
||||
if (parseResp.getSelectedParses().isEmpty()) {
|
||||
errMsg.append(parseResp.getErrorMsg());
|
||||
continue;
|
||||
@@ -139,18 +137,11 @@ public class NL2SQLParser implements ChatQueryParser {
|
||||
SemanticParseInfo userSelectParse = parseContext.getRequest().getSelectedParse();
|
||||
queryNLReq.setSelectedParseInfo(Objects.nonNull(userSelectParse) ? userSelectParse
|
||||
: parseContext.getResponse().getSelectedParses().get(0));
|
||||
parseContext.setResponse(new ChatParseResp(parseContext.getResponse().getQueryId()));
|
||||
|
||||
parseContext.setResponse(new ChatParseResp(parseContext.getResponse().getQueryId()));
|
||||
rewriteMultiTurn(parseContext, queryNLReq);
|
||||
addDynamicExemplars(parseContext, queryNLReq);
|
||||
doParse(queryNLReq, parseContext.getResponse());
|
||||
|
||||
// try again with all semantic fields passed to LLM
|
||||
if (parseContext.getResponse().getState().equals(ParseResp.ParseState.FAILED)) {
|
||||
queryNLReq.setSelectedParseInfo(null);
|
||||
queryNLReq.setMapModeEnum(MapModeEnum.ALL);
|
||||
doParse(queryNLReq, parseContext.getResponse());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,4 @@ public class AgentDO {
|
||||
private String admin;
|
||||
|
||||
private String viewer;
|
||||
|
||||
private String adminOrg;
|
||||
|
||||
private String viewOrg;
|
||||
|
||||
private Integer isOpen;
|
||||
}
|
||||
|
||||
@@ -23,9 +23,6 @@ public class ChatMemoryDO {
|
||||
@TableField("agent_id")
|
||||
private Integer agentId;
|
||||
|
||||
@TableField("query_id")
|
||||
private Long queryId;
|
||||
|
||||
@TableField("question")
|
||||
private String question;
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.tencent.supersonic.chat.server.persistence.mapper.ChatParseMapper;
|
||||
import com.tencent.supersonic.chat.server.persistence.mapper.ChatQueryDOMapper;
|
||||
import com.tencent.supersonic.chat.server.persistence.mapper.custom.ShowCaseCustomMapper;
|
||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
||||
import com.tencent.supersonic.common.pojo.QueryColumn;
|
||||
import com.tencent.supersonic.common.util.JsonUtil;
|
||||
import com.tencent.supersonic.common.util.PageUtils;
|
||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||
@@ -117,20 +116,6 @@ public class ChatQueryRepositoryImpl implements ChatQueryRepository {
|
||||
JsonUtil.toObject(chatQueryDO.getQueryResult(), QueryResult.class);
|
||||
if (queryResult != null) {
|
||||
queryResult.setQueryId(chatQueryDO.getQuestionId());
|
||||
// fix bugs, compatible with bugs caused by history field changes
|
||||
if (!CollectionUtils.isEmpty(queryResult.getQueryColumns())) {
|
||||
List<QueryColumn> queryColumns = queryResult.getQueryColumns().stream().peek(x -> {
|
||||
if (StringUtils.isEmpty(x.getBizName())
|
||||
&& StringUtils.isNotEmpty(x.getNameEn())) {
|
||||
x.setBizName(x.getNameEn());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(x.getBizName())
|
||||
&& StringUtils.isEmpty(x.getNameEn())) {
|
||||
x.setNameEn(x.getBizName());
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
queryResult.setQueryColumns(queryColumns);
|
||||
}
|
||||
queryResp.setQueryResult(queryResult);
|
||||
}
|
||||
queryResp.setSimilarQueries(JSONObject.parseArray(chatQueryDO.getSimilarQueries(),
|
||||
|
||||
@@ -2,7 +2,11 @@ package com.tencent.supersonic.chat.server.pojo;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||
import lombok.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -16,8 +20,6 @@ public class ChatMemory {
|
||||
|
||||
private Integer agentId;
|
||||
|
||||
private Long queryId;
|
||||
|
||||
private String question;
|
||||
|
||||
private String sideInfo;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.tencent.supersonic.chat.server.pojo;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatExecuteReq;
|
||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||
import lombok.Data;
|
||||
@@ -9,7 +8,6 @@ import lombok.Data;
|
||||
@Data
|
||||
public class ExecuteContext {
|
||||
private ChatExecuteReq request;
|
||||
private QueryResult response;
|
||||
private Agent agent;
|
||||
private SemanticParseInfo parseInfo;
|
||||
|
||||
|
||||
@@ -43,17 +43,12 @@ public class DataInterpretProcessor implements ExecuteResultProcessor {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean accept(ExecuteContext executeContext) {
|
||||
Agent agent = executeContext.getAgent();
|
||||
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
||||
return Objects.nonNull(chatApp) && chatApp.isEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ExecuteContext executeContext) {
|
||||
QueryResult queryResult = executeContext.getResponse();
|
||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||
Agent agent = executeContext.getAgent();
|
||||
ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY);
|
||||
if (Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> variable = new HashMap<>();
|
||||
variable.put("question", executeContext.getRequest().getQueryText());
|
||||
|
||||
@@ -27,18 +27,17 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor {
|
||||
private static final int recommend_dimension_size = 5;
|
||||
|
||||
@Override
|
||||
public boolean accept(ExecuteContext executeContext) {
|
||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||
return QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType())
|
||||
&& !CollectionUtils.isEmpty(semanticParseInfo.getMetrics());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ExecuteContext executeContext) {
|
||||
QueryResult queryResult = executeContext.getResponse();
|
||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||
if (!QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType())
|
||||
|| CollectionUtils.isEmpty(semanticParseInfo.getMetrics())) {
|
||||
return;
|
||||
}
|
||||
Long dataSetId = semanticParseInfo.getDataSetId();
|
||||
Optional<SchemaElement> firstMetric = semanticParseInfo.getMetrics().stream().findFirst();
|
||||
if (!firstMetric.isPresent()) {
|
||||
return;
|
||||
}
|
||||
List<SchemaElement> dimensionRecommended =
|
||||
getDimensions(firstMetric.get().getId(), dataSetId);
|
||||
queryResult.setRecommendedDimensions(dimensionRecommended);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.tencent.supersonic.chat.server.processor.execute;
|
||||
|
||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||
import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
||||
|
||||
/** A ExecuteResultProcessor wraps things up before returning execution results to the users. */
|
||||
public interface ExecuteResultProcessor extends ResultProcessor {
|
||||
|
||||
boolean accept(ExecuteContext executeContext);
|
||||
|
||||
void process(ExecuteContext executeContext);
|
||||
void process(ExecuteContext executeContext, QueryResult queryResult);
|
||||
}
|
||||
|
||||
@@ -59,18 +59,14 @@ import static com.tencent.supersonic.common.pojo.Constants.TIME_FORMAT;
|
||||
public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
||||
|
||||
@Override
|
||||
public boolean accept(ExecuteContext executeContext) {
|
||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||
AggregatorConfig aggregatorConfig = ContextUtils.getBean(AggregatorConfig.class);
|
||||
return !CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
||||
&& aggregatorConfig.getEnableRatio()
|
||||
&& QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ExecuteContext executeContext) {
|
||||
QueryResult queryResult = executeContext.getResponse();
|
||||
SemanticParseInfo semanticParseInfo = executeContext.getParseInfo();
|
||||
if (CollectionUtils.isEmpty(semanticParseInfo.getMetrics())
|
||||
|| !aggregatorConfig.getEnableRatio()
|
||||
|| !QueryType.AGGREGATE.equals(semanticParseInfo.getQueryType())) {
|
||||
return;
|
||||
}
|
||||
AggregateInfo aggregateInfo = getAggregateInfo(executeContext.getRequest().getUser(),
|
||||
semanticParseInfo, queryResult);
|
||||
queryResult.setAggregateInfo(aggregateInfo);
|
||||
@@ -142,7 +138,7 @@ public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return queryResult.getQueryColumns().stream()
|
||||
.flatMap(c -> SqlSelectHelper.getFieldsFromExpr(c.getBizName()).stream())
|
||||
.flatMap(c -> SqlSelectHelper.getColumnFromExpr(c.getNameEn()).stream())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@@ -167,16 +163,16 @@ public class MetricRatioCalcProcessor implements ExecuteResultProcessor {
|
||||
|
||||
Map<String, Object> result = queryResp.getResultList().get(0);
|
||||
Optional<QueryColumn> valueColumn = queryResp.getColumns().stream()
|
||||
.filter(c -> c.getBizName().equals(metric.getBizName())).findFirst();
|
||||
.filter(c -> c.getNameEn().equals(metric.getBizName())).findFirst();
|
||||
|
||||
if (!valueColumn.isPresent()) {
|
||||
return metricInfo;
|
||||
}
|
||||
String valueField = String.format("%s_%s", valueColumn.get().getBizName(),
|
||||
String valueField = String.format("%s_%s", valueColumn.get().getNameEn(),
|
||||
aggOperatorEnum.getOperator());
|
||||
if (result.containsKey(valueColumn.get().getBizName())) {
|
||||
if (result.containsKey(valueColumn.get().getNameEn())) {
|
||||
DecimalFormat df = new DecimalFormat("#.####");
|
||||
metricInfo.setValue(df.format(result.get(valueColumn.get().getBizName())));
|
||||
metricInfo.setValue(df.format(result.get(valueColumn.get().getNameEn())));
|
||||
}
|
||||
String ratio = "";
|
||||
if (Objects.nonNull(result.get(valueField))) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.tencent.supersonic.chat.server.processor.execute;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||
import com.tencent.supersonic.chat.server.pojo.ExecuteContext;
|
||||
import com.tencent.supersonic.common.pojo.Constants;
|
||||
import com.tencent.supersonic.common.pojo.enums.DictWordType;
|
||||
@@ -15,7 +16,14 @@ import dev.langchain4j.store.embedding.RetrieveQuery;
|
||||
import dev.langchain4j.store.embedding.RetrieveQueryResult;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -26,20 +34,17 @@ public class MetricRecommendProcessor implements ExecuteResultProcessor {
|
||||
private static final int METRIC_RECOMMEND_SIZE = 5;
|
||||
|
||||
@Override
|
||||
public boolean accept(ExecuteContext executeContext) {
|
||||
SemanticParseInfo parseInfo = executeContext.getParseInfo();
|
||||
return Objects.nonNull(parseInfo.getQueryType())
|
||||
&& parseInfo.getQueryType().equals(QueryType.AGGREGATE)
|
||||
&& !CollectionUtils.isEmpty(parseInfo.getMetrics())
|
||||
&& parseInfo.getMetrics().size() <= METRIC_RECOMMEND_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ExecuteContext executeContext) {
|
||||
public void process(ExecuteContext executeContext, QueryResult queryResult) {
|
||||
fillSimilarMetric(executeContext.getParseInfo());
|
||||
}
|
||||
|
||||
private void fillSimilarMetric(SemanticParseInfo parseInfo) {
|
||||
if (Objects.isNull(parseInfo.getQueryType())
|
||||
|| !parseInfo.getQueryType().equals(QueryType.AGGREGATE)
|
||||
|| parseInfo.getMetrics().size() > METRIC_RECOMMEND_SIZE
|
||||
|| CollectionUtils.isEmpty(parseInfo.getMetrics())) {
|
||||
return;
|
||||
}
|
||||
List<String> metricNames =
|
||||
Collections.singletonList(parseInfo.getMetrics().iterator().next().getName());
|
||||
Map<String, Object> filterCondition = new HashMap<>();
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.tencent.supersonic.chat.server.pojo.ParseContext;
|
||||
import com.tencent.supersonic.common.pojo.ChatApp;
|
||||
import com.tencent.supersonic.common.pojo.enums.AppModule;
|
||||
import com.tencent.supersonic.common.util.ChatAppManager;
|
||||
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||
import com.tencent.supersonic.headless.server.utils.ModelConfigHelper;
|
||||
import dev.langchain4j.data.message.AiMessage;
|
||||
import dev.langchain4j.model.chat.ChatLanguageModel;
|
||||
@@ -27,7 +26,7 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
||||
|
||||
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
|
||||
|
||||
public static final String APP_KEY = "REWRITE_ERROR_MESSAGE";
|
||||
public static final String APP_KEY_ERROR_MESSAGE = "REWRITE_ERROR_MESSAGE";
|
||||
private static final String REWRITE_ERROR_MESSAGE_INSTRUCTION = ""
|
||||
+ "#Role: You are a data business partner who closely interacts with business people.\n"
|
||||
+ "#Task: Your will be provided with user input, system output and some examples, "
|
||||
@@ -38,36 +37,29 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
||||
+ "#Examples: {{examples}}\n" + "#Response: ";
|
||||
|
||||
public ErrorMsgRewriteProcessor() {
|
||||
ChatAppManager.register(APP_KEY,
|
||||
ChatAppManager.register(APP_KEY_ERROR_MESSAGE,
|
||||
ChatApp.builder().prompt(REWRITE_ERROR_MESSAGE_INSTRUCTION).name("异常提示改写")
|
||||
.appModule(AppModule.CHAT).description("通过大模型将异常信息改写为更友好和引导性的提示用语")
|
||||
.enable(true).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(ParseContext parseContext) {
|
||||
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY);
|
||||
return StringUtils.isNotBlank(parseContext.getResponse().getErrorMsg())
|
||||
&& Objects.nonNull(chatApp) && chatApp.isEnable();
|
||||
.enable(false).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ParseContext parseContext) {
|
||||
String errMsg = parseContext.getResponse().getErrorMsg();
|
||||
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY);
|
||||
ChatApp chatApp = parseContext.getAgent().getChatAppConfig().get(APP_KEY_ERROR_MESSAGE);
|
||||
if (StringUtils.isBlank(errMsg) || Objects.isNull(chatApp) || !chatApp.isEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
variables.put("user_question", parseContext.getRequest().getQueryText());
|
||||
variables.put("system_message", errMsg);
|
||||
|
||||
StringBuilder exampleStr = new StringBuilder();
|
||||
if (parseContext.getResponse().getUsedExemplars() != null) {
|
||||
parseContext.getResponse().getUsedExemplars().forEach(e -> exampleStr.append(String
|
||||
.format("<Question:{%s},Schema:{%s}> ", e.getQuestion(), e.getDbSchema())));
|
||||
}
|
||||
if (parseContext.getAgent().getExamples() != null) {
|
||||
parseContext.getAgent().getExamples()
|
||||
.forEach(e -> exampleStr.append(String.format("<Question:{%s}> ", e)));
|
||||
}
|
||||
parseContext.getResponse().getUsedExemplars().forEach(e -> exampleStr.append(
|
||||
String.format("<Question:{%s},Schema:{%s}> ", e.getQuestion(), e.getDbSchema())));
|
||||
parseContext.getAgent().getExamples()
|
||||
.forEach(e -> exampleStr.append(String.format("<Question:{%s}> ", e)));
|
||||
variables.put("examples", exampleStr);
|
||||
|
||||
Prompt prompt = PromptTemplate.from(chatApp.getPrompt()).apply(variables);
|
||||
@@ -76,7 +68,6 @@ public class ErrorMsgRewriteProcessor implements ParseResultProcessor {
|
||||
Response<AiMessage> response = chatLanguageModel.generate(prompt.toUserMessage());
|
||||
String rewrittenMsg = response.content().text();
|
||||
parseContext.getResponse().setErrorMsg(rewrittenMsg);
|
||||
parseContext.getResponse().setState(ParseResp.ParseState.FAILED);
|
||||
keyPipelineLog.info("ErrorMessageProcessor modelReq:\n{} \nmodelResp:\n{}", prompt.text(),
|
||||
rewrittenMsg);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.tencent.supersonic.common.jsqlparser.SqlSelectHelper;
|
||||
import com.tencent.supersonic.common.pojo.DateConf;
|
||||
import com.tencent.supersonic.common.pojo.enums.FilterOperatorEnum;
|
||||
import com.tencent.supersonic.common.pojo.enums.QueryType;
|
||||
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import com.tencent.supersonic.headless.api.pojo.DataSetSchema;
|
||||
import com.tencent.supersonic.headless.api.pojo.SchemaElement;
|
||||
@@ -20,7 +21,12 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -28,12 +34,6 @@ import java.util.stream.Collectors;
|
||||
**/
|
||||
@Slf4j
|
||||
public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
||||
|
||||
@Override
|
||||
public boolean accept(ParseContext parseContext) {
|
||||
return !parseContext.getResponse().getSelectedParses().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ParseContext parseContext) {
|
||||
parseContext.getResponse().getSelectedParses().forEach(p -> {
|
||||
@@ -96,7 +96,7 @@ public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
||||
|
||||
// extract date filter from S2SQL
|
||||
try {
|
||||
if (!CollectionUtils.isEmpty(expressions)) {
|
||||
if (parseInfo.getDateInfo() == null && !CollectionUtils.isEmpty(expressions)) {
|
||||
parseInfo.setDateInfo(extractDateFilter(expressions, dsSchema));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -216,6 +216,9 @@ public class ParseInfoFormatProcessor implements ParseResultProcessor {
|
||||
}
|
||||
|
||||
private static boolean isPartitionDimension(DataSetSchema dataSetSchema, String sqlFieldName) {
|
||||
if (TimeDimensionEnum.containsTimeDimension(sqlFieldName)) {
|
||||
return true;
|
||||
}
|
||||
if (Objects.isNull(dataSetSchema) || Objects.isNull(dataSetSchema.getPartitionDimension())
|
||||
|| Objects.isNull(dataSetSchema.getPartitionDimension().getName())) {
|
||||
return false;
|
||||
|
||||
@@ -6,7 +6,5 @@ import com.tencent.supersonic.chat.server.processor.ResultProcessor;
|
||||
/** A ParseResultProcessor wraps things up before returning parsing results to the users. */
|
||||
public interface ParseResultProcessor extends ResultProcessor {
|
||||
|
||||
boolean accept(ParseContext parseContext);
|
||||
|
||||
void process(ParseContext parseContext);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,6 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
public class QueryRecommendProcessor implements ParseResultProcessor {
|
||||
|
||||
@Override
|
||||
public boolean accept(ParseContext parseContext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ParseContext parseContext) {
|
||||
CompletableFuture.runAsync(() -> doProcess(parseContext));
|
||||
|
||||
@@ -10,11 +10,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
public class TimeCostCalcProcessor implements ParseResultProcessor {
|
||||
|
||||
@Override
|
||||
public boolean accept(ParseContext parseContext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ParseContext parseContext) {
|
||||
ChatParseResp parseResp = parseContext.getResponse();
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ChatController {
|
||||
}
|
||||
|
||||
@PostMapping("/updateQAFeedback")
|
||||
public Boolean updateQAFeedback(@RequestParam(value = "id") Long id,
|
||||
public Boolean updateQAFeedback(@RequestParam(value = "id") Integer id,
|
||||
@RequestParam(value = "score") Integer score,
|
||||
@RequestParam(value = "feedback", required = false) String feedback) {
|
||||
return chatService.updateFeedback(id, score, feedback);
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.tencent.supersonic.chat.server.persistence.dataobject.ChatParseDO;
|
||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDO;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -23,7 +24,7 @@ public interface ChatManageService {
|
||||
|
||||
boolean updateChatName(Long chatId, String chatName, String userName);
|
||||
|
||||
boolean updateFeedback(Long id, Integer score, String feedback);
|
||||
boolean updateFeedback(Integer id, Integer score, String feedback);
|
||||
|
||||
boolean updateChatIsTop(Long chatId, int isTop);
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ public interface MemoryService {
|
||||
|
||||
void updateMemory(ChatMemoryUpdateReq chatMemoryUpdateReq, User user);
|
||||
|
||||
void updateMemory(ChatMemory memory);
|
||||
|
||||
void batchDelete(List<Long> ids);
|
||||
|
||||
PageInfo<ChatMemory> pageMemories(PageMemoryReq pageMemoryReq);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.tencent.supersonic.chat.server.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.tencent.supersonic.auth.api.authentication.service.UserService;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||
import com.tencent.supersonic.chat.server.agent.Agent;
|
||||
@@ -21,14 +20,13 @@ import com.tencent.supersonic.common.util.JsonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@@ -44,12 +42,7 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
||||
@Autowired
|
||||
private ChatModelService chatModelService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("chatExecutor")
|
||||
private ThreadPoolExecutor executor;
|
||||
private ExecutorService executorService = Executors.newFixedThreadPool(1);
|
||||
|
||||
@Override
|
||||
public List<Agent> getAgents(User user, AuthType authType) {
|
||||
@@ -58,19 +51,17 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
||||
}
|
||||
|
||||
private boolean filterByAuth(Agent agent, User user, AuthType authType) {
|
||||
Set<String> orgIds = userService.getUserAllOrgId(user.getName());
|
||||
|
||||
if (user.isSuperAdmin() || agent.openToAll()
|
||||
|| user.getName().equals(agent.getCreatedBy())) {
|
||||
if (user.isSuperAdmin() || user.getName().equals(agent.getCreatedBy())) {
|
||||
return true;
|
||||
}
|
||||
authType = authType == null ? AuthType.VIEWER : authType;
|
||||
switch (authType) {
|
||||
case ADMIN:
|
||||
return checkAdminPermission(orgIds, user, agent);
|
||||
return agent.contains(user, Agent::getAdmins);
|
||||
case VIEWER:
|
||||
default:
|
||||
return checkViewPermission(orgIds, user, agent);
|
||||
return agent.contains(user, Agent::getAdmins)
|
||||
|| agent.contains(user, Agent::getViewers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +108,7 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
||||
* @param agent
|
||||
*/
|
||||
private void executeAgentExamplesAsync(Agent agent) {
|
||||
executor.execute(() -> doExecuteAgentExamples(agent));
|
||||
executorService.execute(() -> doExecuteAgentExamples(agent));
|
||||
}
|
||||
|
||||
private synchronized void doExecuteAgentExamples(Agent agent) {
|
||||
@@ -168,9 +159,6 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
||||
});
|
||||
agent.setAdmins(JsonUtil.toList(agentDO.getAdmin(), String.class));
|
||||
agent.setViewers(JsonUtil.toList(agentDO.getViewer(), String.class));
|
||||
agent.setAdminOrgs(JsonUtil.toList(agentDO.getAdminOrg(), String.class));
|
||||
agent.setViewOrgs(JsonUtil.toList(agentDO.getViewOrg(), String.class));
|
||||
agent.setIsOpen(agentDO.getIsOpen());
|
||||
return agent;
|
||||
}
|
||||
|
||||
@@ -183,56 +171,9 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
|
||||
agentDO.setVisualConfig(JsonUtil.toString(agent.getVisualConfig()));
|
||||
agentDO.setAdmin(JsonUtil.toString(agent.getAdmins()));
|
||||
agentDO.setViewer(JsonUtil.toString(agent.getViewers()));
|
||||
agentDO.setAdminOrg(JsonUtil.toString(agent.getAdminOrgs()));
|
||||
agentDO.setViewOrg(JsonUtil.toString(agent.getViewOrgs()));
|
||||
agentDO.setIsOpen(agent.getIsOpen());
|
||||
if (agentDO.getStatus() == null) {
|
||||
agentDO.setStatus(1);
|
||||
}
|
||||
return agentDO;
|
||||
}
|
||||
|
||||
private boolean checkAdminPermission(Set<String> orgIds, User user, Agent agent) {
|
||||
List<String> admins = agent.getAdmins();
|
||||
List<String> adminOrgs = agent.getAdminOrgs();
|
||||
if (user.isSuperAdmin()) {
|
||||
return true;
|
||||
}
|
||||
if (admins.contains(user.getName()) || agent.getCreatedBy().equals(user.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(adminOrgs)) {
|
||||
return false;
|
||||
}
|
||||
for (String orgId : orgIds) {
|
||||
if (adminOrgs.contains(orgId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkViewPermission(Set<String> orgIds, User user, Agent agent) {
|
||||
if (checkAdminPermission(orgIds, user, agent)) {
|
||||
return true;
|
||||
}
|
||||
List<String> viewers = agent.getViewers();
|
||||
List<String> viewOrgs = agent.getViewOrgs();
|
||||
if (agent.openToAll()) {
|
||||
return true;
|
||||
}
|
||||
if (viewers.contains(user.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(viewOrgs)) {
|
||||
return false;
|
||||
}
|
||||
for (String orgId : orgIds) {
|
||||
if (viewOrgs.contains(orgId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package com.tencent.supersonic.chat.server.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryStatus;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.*;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatExecuteReq;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatParseReq;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.PageQueryInfoReq;
|
||||
import com.tencent.supersonic.chat.api.pojo.response.ChatParseResp;
|
||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResp;
|
||||
import com.tencent.supersonic.chat.api.pojo.response.QueryResult;
|
||||
@@ -15,12 +15,11 @@ import com.tencent.supersonic.chat.server.persistence.dataobject.ChatQueryDO;
|
||||
import com.tencent.supersonic.chat.server.persistence.dataobject.QueryDO;
|
||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatQueryRepository;
|
||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatRepository;
|
||||
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||
import com.tencent.supersonic.chat.server.service.ChatManageService;
|
||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import com.tencent.supersonic.common.util.JsonUtil;
|
||||
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
|
||||
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -39,8 +38,6 @@ public class ChatManageServiceImpl implements ChatManageService {
|
||||
private ChatRepository chatRepository;
|
||||
@Autowired
|
||||
private ChatQueryRepository chatQueryRepository;
|
||||
@Autowired
|
||||
private MemoryService memoryService;
|
||||
|
||||
@Override
|
||||
public Long addChat(User user, String chatName, Integer agentId) {
|
||||
@@ -67,28 +64,11 @@ public class ChatManageServiceImpl implements ChatManageService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateFeedback(Long id, Integer score, String feedback) {
|
||||
public boolean updateFeedback(Integer id, Integer score, String feedback) {
|
||||
QueryDO intelligentQueryDO = new QueryDO();
|
||||
intelligentQueryDO.setId(id);
|
||||
intelligentQueryDO.setQuestionId(id);
|
||||
intelligentQueryDO.setScore(score);
|
||||
intelligentQueryDO.setFeedback(feedback);
|
||||
|
||||
// enable or disable memory based on user feedback
|
||||
if (score >= 5 || score <= 1) {
|
||||
ChatMemoryFilter memoryFilter = ChatMemoryFilter.builder().queryId(id).build();
|
||||
List<ChatMemory> memories = memoryService.getMemories(memoryFilter);
|
||||
memories.forEach(m -> {
|
||||
MemoryStatus status = score >= 5 ? MemoryStatus.ENABLED : MemoryStatus.DISABLED;
|
||||
MemoryReviewResult reviewResult =
|
||||
score >= 5 ? MemoryReviewResult.POSITIVE : MemoryReviewResult.NEGATIVE;
|
||||
ChatMemoryUpdateReq memoryUpdateReq = ChatMemoryUpdateReq.builder().id(m.getId())
|
||||
.status(status).humanReviewRet(reviewResult)
|
||||
.humanReviewCmt("Reviewed as per user feedback").build();
|
||||
memoryService.updateMemory(memoryUpdateReq, User.getDefaultUser());
|
||||
});
|
||||
}
|
||||
|
||||
return chatRepository.updateFeedback(intelligentQueryDO);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,17 +91,11 @@ public class ChatQueryServiceImpl implements ChatQueryService {
|
||||
Long queryId = chatParseReq.getQueryId();
|
||||
if (Objects.isNull(queryId)) {
|
||||
queryId = chatManageService.createChatQuery(chatParseReq);
|
||||
chatParseReq.setQueryId(queryId);
|
||||
}
|
||||
|
||||
ParseContext parseContext = buildParseContext(chatParseReq, new ChatParseResp(queryId));
|
||||
chatQueryParsers.forEach(p -> p.parse(parseContext));
|
||||
|
||||
for (ParseResultProcessor processor : parseResultProcessors) {
|
||||
if (processor.accept(parseContext)) {
|
||||
processor.process(parseContext);
|
||||
}
|
||||
}
|
||||
parseResultProcessors.forEach(p -> p.process(parseContext));
|
||||
|
||||
if (!parseContext.needFeedback()) {
|
||||
chatManageService.batchAddParse(chatParseReq, parseContext.getResponse());
|
||||
@@ -122,12 +116,9 @@ public class ChatQueryServiceImpl implements ChatQueryService {
|
||||
}
|
||||
}
|
||||
|
||||
executeContext.setResponse(queryResult);
|
||||
if (queryResult != null) {
|
||||
for (ExecuteResultProcessor processor : executeResultProcessors) {
|
||||
if (processor.accept(executeContext)) {
|
||||
processor.process(executeContext);
|
||||
}
|
||||
processor.process(executeContext, queryResult);
|
||||
}
|
||||
saveQueryResult(chatExecuteReq, queryResult);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.tencent.supersonic.chat.server.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.tencent.supersonic.chat.api.pojo.enums.MemoryReviewResult;
|
||||
@@ -10,7 +9,6 @@ import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryFilter;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.ChatMemoryUpdateReq;
|
||||
import com.tencent.supersonic.chat.api.pojo.request.PageMemoryReq;
|
||||
import com.tencent.supersonic.chat.server.persistence.dataobject.ChatMemoryDO;
|
||||
import com.tencent.supersonic.chat.server.persistence.mapper.ChatMemoryMapper;
|
||||
import com.tencent.supersonic.chat.server.persistence.repository.ChatMemoryRepository;
|
||||
import com.tencent.supersonic.chat.server.pojo.ChatMemory;
|
||||
import com.tencent.supersonic.chat.server.service.MemoryService;
|
||||
@@ -18,6 +16,7 @@ import com.tencent.supersonic.common.config.EmbeddingConfig;
|
||||
import com.tencent.supersonic.common.pojo.Text2SQLExemplar;
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import com.tencent.supersonic.common.service.ExemplarService;
|
||||
import com.tencent.supersonic.common.util.BeanMapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -35,9 +34,6 @@ public class MemoryServiceImpl implements MemoryService {
|
||||
@Autowired
|
||||
private ChatMemoryRepository chatMemoryRepository;
|
||||
|
||||
@Autowired
|
||||
private ChatMemoryMapper chatMemoryMapper;
|
||||
|
||||
@Autowired
|
||||
private ExemplarService exemplarService;
|
||||
|
||||
@@ -61,36 +57,20 @@ public class MemoryServiceImpl implements MemoryService {
|
||||
ChatMemoryDO chatMemoryDO = chatMemoryRepository.getMemory(chatMemoryUpdateReq.getId());
|
||||
boolean hadEnabled =
|
||||
MemoryStatus.ENABLED.toString().equals(chatMemoryDO.getStatus().trim());
|
||||
chatMemoryDO.setUpdatedBy(user.getName());
|
||||
chatMemoryDO.setUpdatedAt(new Date());
|
||||
BeanMapper.mapper(chatMemoryUpdateReq, chatMemoryDO);
|
||||
if (MemoryStatus.ENABLED.equals(chatMemoryUpdateReq.getStatus()) && !hadEnabled) {
|
||||
enableMemory(chatMemoryDO);
|
||||
} else if (MemoryStatus.DISABLED.equals(chatMemoryUpdateReq.getStatus()) && hadEnabled) {
|
||||
disableMemory(chatMemoryDO);
|
||||
}
|
||||
chatMemoryRepository.updateMemory(chatMemoryDO);
|
||||
}
|
||||
|
||||
LambdaUpdateWrapper<ChatMemoryDO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(ChatMemoryDO::getId, chatMemoryDO.getId());
|
||||
if (Objects.nonNull(chatMemoryUpdateReq.getStatus())) {
|
||||
updateWrapper.set(ChatMemoryDO::getStatus, chatMemoryUpdateReq.getStatus());
|
||||
}
|
||||
if (Objects.nonNull(chatMemoryUpdateReq.getLlmReviewRet())) {
|
||||
updateWrapper.set(ChatMemoryDO::getLlmReviewRet,
|
||||
chatMemoryUpdateReq.getLlmReviewRet().toString());
|
||||
}
|
||||
if (Objects.nonNull(chatMemoryUpdateReq.getLlmReviewCmt())) {
|
||||
updateWrapper.set(ChatMemoryDO::getLlmReviewCmt, chatMemoryUpdateReq.getLlmReviewCmt());
|
||||
}
|
||||
if (Objects.nonNull(chatMemoryUpdateReq.getHumanReviewRet())) {
|
||||
updateWrapper.set(ChatMemoryDO::getHumanReviewRet,
|
||||
chatMemoryUpdateReq.getHumanReviewRet().toString());
|
||||
}
|
||||
if (Objects.nonNull(chatMemoryUpdateReq.getHumanReviewCmt())) {
|
||||
updateWrapper.set(ChatMemoryDO::getHumanReviewCmt,
|
||||
chatMemoryUpdateReq.getHumanReviewCmt());
|
||||
}
|
||||
updateWrapper.set(ChatMemoryDO::getUpdatedAt, new Date());
|
||||
updateWrapper.set(ChatMemoryDO::getUpdatedBy, user.getName());
|
||||
|
||||
chatMemoryMapper.update(updateWrapper);
|
||||
@Override
|
||||
public void updateMemory(ChatMemory memory) {
|
||||
chatMemoryRepository.updateMemory(getMemoryDO(memory));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,9 +93,6 @@ public class MemoryServiceImpl implements MemoryService {
|
||||
if (chatMemoryFilter.getAgentId() != null) {
|
||||
queryWrapper.lambda().eq(ChatMemoryDO::getAgentId, chatMemoryFilter.getAgentId());
|
||||
}
|
||||
if (chatMemoryFilter.getQueryId() != null) {
|
||||
queryWrapper.lambda().eq(ChatMemoryDO::getQueryId, chatMemoryFilter.getQueryId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(chatMemoryFilter.getQuestion())) {
|
||||
queryWrapper.lambda().like(ChatMemoryDO::getQuestion, chatMemoryFilter.getQuestion());
|
||||
}
|
||||
@@ -143,7 +120,7 @@ public class MemoryServiceImpl implements MemoryService {
|
||||
return chatMemoryDOS.stream().map(this::getMemory).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void enableMemory(ChatMemoryDO memory) {
|
||||
private void enableMemory(ChatMemoryDO memory) {
|
||||
memory.setStatus(MemoryStatus.ENABLED.toString());
|
||||
exemplarService.storeExemplar(embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
||||
Text2SQLExemplar.builder().question(memory.getQuestion())
|
||||
@@ -151,7 +128,7 @@ public class MemoryServiceImpl implements MemoryService {
|
||||
.sql(memory.getS2sql()).build());
|
||||
}
|
||||
|
||||
public void disableMemory(ChatMemoryDO memory) {
|
||||
private void disableMemory(ChatMemoryDO memory) {
|
||||
memory.setStatus(MemoryStatus.DISABLED.toString());
|
||||
exemplarService.removeExemplar(embeddingConfig.getMemoryCollectionName(memory.getAgentId()),
|
||||
Text2SQLExemplar.builder().question(memory.getQuestion())
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ResultFormatter {
|
||||
}
|
||||
for (Map<String, Object> row : queryResults) {
|
||||
for (QueryColumn column : queryColumns) {
|
||||
String columnKey = column.getBizName();
|
||||
String columnKey = column.getNameEn();
|
||||
Object value = row.get(columnKey);
|
||||
table.append("| ").append(value != null ? value.toString() : "").append(" ");
|
||||
}
|
||||
|
||||
@@ -174,10 +174,6 @@
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-milvus</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-opensearch</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.langchain4j</groupId>
|
||||
<artifactId>langchain4j-pgvector</artifactId>
|
||||
@@ -246,10 +242,6 @@
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
|
||||
@@ -81,7 +81,7 @@ public class Configuration {
|
||||
.setUnquotedCasing(Casing.TO_UPPER).setConformance(sqlDialect.getConformance())
|
||||
.setLex(Lex.BIG_QUERY);
|
||||
if (EngineType.HANADB.equals(engineType)) {
|
||||
parserConfig = parserConfig.setQuoting(Quoting.DOUBLE_QUOTE);
|
||||
parserConfig = parserConfig.setQuoting(Quoting.DOUBLE_QUOTE);
|
||||
}
|
||||
parserConfig = parserConfig.setQuotedCasing(Casing.UNCHANGED);
|
||||
parserConfig = parserConfig.setUnquotedCasing(Casing.UNCHANGED);
|
||||
|
||||
@@ -21,11 +21,10 @@ public class SqlDialectFactory {
|
||||
.withDatabaseProduct(DatabaseProduct.BIG_QUERY).withLiteralQuoteString("'")
|
||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(false);
|
||||
public static final Context HANADB_CONTEXT =
|
||||
SqlDialect.EMPTY_CONTEXT.withDatabaseProduct(DatabaseProduct.BIG_QUERY)
|
||||
.withLiteralQuoteString("'").withIdentifierQuoteString("\"")
|
||||
.withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
||||
public static final Context HANADB_CONTEXT = SqlDialect.EMPTY_CONTEXT
|
||||
.withDatabaseProduct(DatabaseProduct.BIG_QUERY).withLiteralQuoteString("'")
|
||||
.withIdentifierQuoteString("\"").withLiteralEscapedQuoteString("''").withUnquotedCasing(Casing.UNCHANGED)
|
||||
.withQuotedCasing(Casing.UNCHANGED).withCaseSensitive(true);
|
||||
private static Map<EngineType, SemanticSqlDialect> sqlDialectMap;
|
||||
|
||||
static {
|
||||
|
||||
@@ -17,10 +17,9 @@ import java.util.List;
|
||||
public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
||||
private static final String MODULE_NAME = "向量数据库配置";
|
||||
|
||||
public static final Parameter EMBEDDING_STORE_PROVIDER =
|
||||
new Parameter("s2.embedding.store.provider", EmbeddingStoreType.IN_MEMORY.name(),
|
||||
"向量库类型", "目前支持四种类型:IN_MEMORY、MILVUS、CHROMA、PGVECTOR、OPENSEARCH", "list",
|
||||
MODULE_NAME, getCandidateValues());
|
||||
public static final Parameter EMBEDDING_STORE_PROVIDER = new Parameter(
|
||||
"s2.embedding.store.provider", EmbeddingStoreType.IN_MEMORY.name(), "向量库类型",
|
||||
"目前支持四种类型:IN_MEMORY、MILVUS、CHROMA、PGVECTOR", "list", MODULE_NAME, getCandidateValues());
|
||||
|
||||
public static final Parameter EMBEDDING_STORE_BASE_URL =
|
||||
new Parameter("s2.embedding.store.base.url", "", "BaseUrl", "", "string", MODULE_NAME,
|
||||
@@ -88,18 +87,16 @@ public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
||||
private static ArrayList<String> getCandidateValues() {
|
||||
return Lists.newArrayList(EmbeddingStoreType.IN_MEMORY.name(),
|
||||
EmbeddingStoreType.MILVUS.name(), EmbeddingStoreType.CHROMA.name(),
|
||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name());
|
||||
EmbeddingStoreType.PGVECTOR.name());
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getBaseUrlDependency() {
|
||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||
EmbeddingStoreType.CHROMA.name(), EmbeddingStoreType.PGVECTOR.name(),
|
||||
EmbeddingStoreType.OPENSEARCH.name()),
|
||||
EmbeddingStoreType.CHROMA.name(), EmbeddingStoreType.PGVECTOR.name()),
|
||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "http://localhost:19530",
|
||||
EmbeddingStoreType.CHROMA.name(), "http://localhost:8000",
|
||||
EmbeddingStoreType.PGVECTOR.name(), "127.0.0.1",
|
||||
EmbeddingStoreType.OPENSEARCH.name(), "http://localhost:9200"));
|
||||
EmbeddingStoreType.PGVECTOR.name(), "127.0.0.1"));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getApiKeyDependency() {
|
||||
@@ -117,19 +114,17 @@ public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
||||
private static List<Parameter.Dependency> getDimensionDependency() {
|
||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
||||
EmbeddingStoreType.PGVECTOR.name()),
|
||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "384",
|
||||
EmbeddingStoreType.PGVECTOR.name(), "512",
|
||||
EmbeddingStoreType.OPENSEARCH.name(), "512"));
|
||||
EmbeddingStoreType.PGVECTOR.name(), "512"));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getDatabaseNameDependency() {
|
||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
||||
EmbeddingStoreType.PGVECTOR.name()),
|
||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "",
|
||||
EmbeddingStoreType.PGVECTOR.name(), "postgres",
|
||||
EmbeddingStoreType.OPENSEARCH.name(), "ai_sql"));
|
||||
EmbeddingStoreType.PGVECTOR.name(), "postgres"));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getPortDependency() {
|
||||
@@ -141,18 +136,16 @@ public class EmbeddingStoreParameterConfig extends ParameterConfig {
|
||||
private static List<Parameter.Dependency> getUserDependency() {
|
||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
||||
EmbeddingStoreType.PGVECTOR.name()),
|
||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "milvus",
|
||||
EmbeddingStoreType.PGVECTOR.name(), "postgres",
|
||||
EmbeddingStoreType.OPENSEARCH.name(), "opensearch"));
|
||||
EmbeddingStoreType.PGVECTOR.name(), "postgres"));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getPasswordDependency() {
|
||||
return getDependency(EMBEDDING_STORE_PROVIDER.getName(),
|
||||
Lists.newArrayList(EmbeddingStoreType.MILVUS.name(),
|
||||
EmbeddingStoreType.PGVECTOR.name(), EmbeddingStoreType.OPENSEARCH.name()),
|
||||
EmbeddingStoreType.PGVECTOR.name()),
|
||||
ImmutableMap.of(EmbeddingStoreType.MILVUS.name(), "milvus",
|
||||
EmbeddingStoreType.PGVECTOR.name(), "postgres",
|
||||
EmbeddingStoreType.OPENSEARCH.name(), "opensearch"));
|
||||
EmbeddingStoreType.PGVECTOR.name(), "postgres"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.tencent.supersonic.common.config;
|
||||
|
||||
import com.tencent.supersonic.common.util.S2ThreadContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class ThreadContextConfig {
|
||||
|
||||
@Bean
|
||||
public S2ThreadContext s2ThreadContext() {
|
||||
return new S2ThreadContext();
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.tencent.supersonic.common.config;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
public class ThreadPoolConfig {
|
||||
|
||||
@Bean("eventExecutor")
|
||||
public ThreadPoolExecutor getTaskEventExecutor() {
|
||||
return new ThreadPoolExecutor(4, 8, 60 * 3, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(1024),
|
||||
new ThreadFactoryBuilder().setNameFormat("supersonic-event-pool-").build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
@Bean("commonExecutor")
|
||||
public ThreadPoolExecutor getCommonExecutor() {
|
||||
return new ThreadPoolExecutor(8, 16, 60 * 3, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(1024),
|
||||
new ThreadFactoryBuilder().setNameFormat("supersonic-common-pool-").build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
@Bean("mapExecutor")
|
||||
public ThreadPoolExecutor getMapExecutor() {
|
||||
return new ThreadPoolExecutor(8, 16, 60 * 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
|
||||
new ThreadFactoryBuilder().setNameFormat("supersonic-map-pool-").build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
@Bean("chatExecutor")
|
||||
public ThreadPoolExecutor getChatExecutor() {
|
||||
return new ThreadPoolExecutor(8, 16, 60 * 3, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<>(1024),
|
||||
new ThreadFactoryBuilder().setNameFormat("supersonic-chat-pool-").build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class AliasAcquireVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
private Set<String> aliases;
|
||||
|
||||
public AliasAcquireVisitor(Set<String> aliases) {
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SelectItem selectItem) {
|
||||
Alias alias = selectItem.getAlias();
|
||||
if (alias != null) {
|
||||
aliases.add(alias.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
|
||||
@@ -12,7 +11,6 @@ import java.util.Set;
|
||||
public class FieldAcquireVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
private Set<String> fields;
|
||||
private Set<String> aliases = Sets.newHashSet();
|
||||
|
||||
public FieldAcquireVisitor(Set<String> fields) {
|
||||
this.fields = fields;
|
||||
@@ -28,9 +26,8 @@ public class FieldAcquireVisitor extends ExpressionVisitorAdapter {
|
||||
public void visit(SelectItem selectItem) {
|
||||
Alias alias = selectItem.getAlias();
|
||||
if (alias != null) {
|
||||
aliases.add(alias.getName());
|
||||
fields.add(alias.getName());
|
||||
}
|
||||
|
||||
Expression expression = selectItem.getExpression();
|
||||
if (expression != null) {
|
||||
expression.accept(this);
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
import net.sf.jsqlparser.statement.select.SelectItemVisitorAdapter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FieldAliasReplaceNameVisitor extends SelectItemVisitorAdapter {
|
||||
private Map<String, String> fieldNameMap;
|
||||
|
||||
private Map<String, String> aliasToActualExpression = new HashMap<>();
|
||||
|
||||
public FieldAliasReplaceNameVisitor(Map<String, String> fieldNameMap) {
|
||||
this.fieldNameMap = fieldNameMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SelectItem selectExpressionItem) {
|
||||
Alias alias = selectExpressionItem.getAlias();
|
||||
if (alias == null) {
|
||||
return;
|
||||
}
|
||||
String aliasName = alias.getName();
|
||||
String replaceValue = fieldNameMap.get(aliasName);
|
||||
if (StringUtils.isBlank(replaceValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aliasToActualExpression.put(aliasName, replaceValue);
|
||||
alias.setName(replaceValue);
|
||||
}
|
||||
|
||||
public Map<String, String> getAliasToActualExpression() {
|
||||
return aliasToActualExpression;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
import net.sf.jsqlparser.statement.select.SelectItemVisitorAdapter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class FieldAliasReplaceWithBackticksVisitor extends SelectItemVisitorAdapter {
|
||||
|
||||
private Map<String, String> fieldAliasReplacedMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void visit(SelectItem selectExpressionItem) {
|
||||
Alias alias = selectExpressionItem.getAlias();
|
||||
if (alias == null) {
|
||||
return;
|
||||
}
|
||||
String aliasName = alias.getName();
|
||||
String replaceValue = addBackticks(aliasName);
|
||||
if (StringUtils.isBlank(replaceValue)) {
|
||||
return;
|
||||
}
|
||||
alias.setName(replaceValue);
|
||||
fieldAliasReplacedMap.put(aliasName, replaceValue);
|
||||
}
|
||||
|
||||
private String addBackticks(String aliasName) {
|
||||
if (StringUtils.isBlank(aliasName)) {
|
||||
return "";
|
||||
}
|
||||
if (aliasName.startsWith("`") && aliasName.endsWith("`")) {
|
||||
return "";
|
||||
}
|
||||
return "`" + aliasName + "`";
|
||||
}
|
||||
|
||||
public Map<String, String> getFieldAliasReplacedMap() {
|
||||
return fieldAliasReplacedMap;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,15 @@ import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import net.sf.jsqlparser.expression.StringValue;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
@@ -26,29 +34,6 @@ public class FieldAndValueAcquireVisitor extends ExpressionVisitorAdapter {
|
||||
this.fieldExpressions = fieldExpressions;
|
||||
}
|
||||
|
||||
public void visit(Between between) {
|
||||
Expression leftExpression = between.getLeftExpression();
|
||||
String columnName = null;
|
||||
if (leftExpression instanceof Column) {
|
||||
Column column = (Column) leftExpression;
|
||||
columnName = column.getColumnName();
|
||||
}
|
||||
Expression betweenExpressionStart = between.getBetweenExpressionStart();
|
||||
Expression betweenExpressionEnd = between.getBetweenExpressionEnd();
|
||||
|
||||
FieldExpression fieldExpressionStart = new FieldExpression();
|
||||
fieldExpressionStart.setFieldName(columnName);
|
||||
fieldExpressionStart.setFieldValue(getFieldValue(betweenExpressionStart));
|
||||
fieldExpressionStart.setOperator(JsqlConstants.GREATER_THAN_EQUALS);
|
||||
fieldExpressions.add(fieldExpressionStart);
|
||||
|
||||
FieldExpression fieldExpressionEnd = new FieldExpression();
|
||||
fieldExpressionEnd.setFieldName(columnName);
|
||||
fieldExpressionEnd.setFieldValue(getFieldValue(betweenExpressionEnd));
|
||||
fieldExpressionEnd.setOperator(JsqlConstants.MINOR_THAN_EQUALS);
|
||||
fieldExpressions.add(fieldExpressionEnd);
|
||||
}
|
||||
|
||||
public void visit(LikeExpression expr) {
|
||||
Expression leftExpression = expr.getLeftExpression();
|
||||
Expression rightExpression = expr.getRightExpression();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.AnalyticExpression;
|
||||
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
|
||||
@@ -13,7 +14,6 @@ import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class FieldReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
private Map<String, String> fieldNameMap;
|
||||
private ThreadLocal<Boolean> exactReplace = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
@@ -24,7 +24,8 @@ public class FieldReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
@Override
|
||||
public void visit(Column column) {
|
||||
SqlReplaceHelper.replaceColumn(column, fieldNameMap, exactReplace.get());
|
||||
ReplaceService replaceService = ContextUtils.getBean(ReplaceService.class);
|
||||
replaceService.replaceColumn(column, fieldNameMap, exactReplace.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.expression.DoubleValue;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import net.sf.jsqlparser.expression.StringValue;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -15,14 +28,13 @@ import java.util.Objects;
|
||||
@Slf4j
|
||||
public class FieldValueReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
private final boolean exactReplace;
|
||||
|
||||
private final Map<String, Map<String, String>> filedNameToValueMap;
|
||||
private boolean exactReplace;
|
||||
private Map<String, Map<String, String>> filedNameToValueMap;
|
||||
|
||||
public FieldValueReplaceVisitor(boolean exactReplace,
|
||||
Map<String, Map<String, String>> filedNameToValueMap) {
|
||||
this.filedNameToValueMap = filedNameToValueMap;
|
||||
this.exactReplace = exactReplace;
|
||||
this.filedNameToValueMap = filedNameToValueMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,8 +137,9 @@ public class FieldValueReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
private String getReplaceValue(Map<String, String> valueMap, String beforeValue) {
|
||||
String afterValue = valueMap.get(String.valueOf(beforeValue));
|
||||
if (StringUtils.isEmpty(afterValue)) {
|
||||
return SqlReplaceHelper.getReplaceValue(beforeValue, valueMap, exactReplace);
|
||||
if (StringUtils.isEmpty(afterValue) && !exactReplace) {
|
||||
ReplaceService replaceService = ContextUtils.getBean(ReplaceService.class);
|
||||
return replaceService.getReplaceValue(beforeValue, valueMap, false);
|
||||
}
|
||||
return afterValue;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
@@ -14,8 +15,8 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
public class GroupByReplaceVisitor implements GroupByVisitor {
|
||||
|
||||
private final boolean exactReplace;
|
||||
private final Map<String, String> fieldNameMap;
|
||||
private Map<String, String> fieldNameMap;
|
||||
private boolean exactReplace;
|
||||
|
||||
public GroupByReplaceVisitor(Map<String, String> fieldNameMap, boolean exactReplace) {
|
||||
this.fieldNameMap = fieldNameMap;
|
||||
@@ -33,10 +34,11 @@ public class GroupByReplaceVisitor implements GroupByVisitor {
|
||||
}
|
||||
|
||||
private void replaceExpression(Expression expression) {
|
||||
ReplaceService replaceService = ContextUtils.getBean(ReplaceService.class);
|
||||
if (expression instanceof Column) {
|
||||
SqlReplaceHelper.replaceColumn((Column) expression, fieldNameMap, exactReplace);
|
||||
replaceService.replaceColumn((Column) expression, fieldNameMap, exactReplace);
|
||||
} else if (expression instanceof Function) {
|
||||
SqlReplaceHelper.replaceFunction((Function) expression, fieldNameMap, exactReplace);
|
||||
replaceService.replaceFunction((Function) expression, fieldNameMap, exactReplace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ public class JsqlConstants {
|
||||
public static final String EQUAL_CONSTANT = " 1 = 1 ";
|
||||
public static final String IN_CONSTANT = " 1 in (1) ";
|
||||
public static final String LIKE_CONSTANT = "1 like 1";
|
||||
public static final String BETWEEN_AND_CONSTANT = "1 between 2 and 3";
|
||||
public static final String IN = "IN";
|
||||
public static final Map<String, String> rightMap = Stream.of(
|
||||
new AbstractMap.SimpleEntry<>("<=", "<="), new AbstractMap.SimpleEntry<>("<", "<"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
@@ -9,9 +10,8 @@ import net.sf.jsqlparser.statement.select.OrderByVisitorAdapter;
|
||||
import java.util.Map;
|
||||
|
||||
public class OrderByReplaceVisitor extends OrderByVisitorAdapter {
|
||||
|
||||
private final boolean exactReplace;
|
||||
private final Map<String, String> fieldNameMap;
|
||||
private Map<String, String> fieldNameMap;
|
||||
private boolean exactReplace;
|
||||
|
||||
public OrderByReplaceVisitor(Map<String, String> fieldNameMap, boolean exactReplace) {
|
||||
this.fieldNameMap = fieldNameMap;
|
||||
@@ -21,11 +21,12 @@ public class OrderByReplaceVisitor extends OrderByVisitorAdapter {
|
||||
@Override
|
||||
public void visit(OrderByElement orderBy) {
|
||||
Expression expression = orderBy.getExpression();
|
||||
ReplaceService replaceService = ContextUtils.getBean(ReplaceService.class);
|
||||
if (expression instanceof Column) {
|
||||
SqlReplaceHelper.replaceColumn((Column) expression, fieldNameMap, exactReplace);
|
||||
replaceService.replaceColumn((Column) expression, fieldNameMap, exactReplace);
|
||||
}
|
||||
if (expression instanceof Function) {
|
||||
SqlReplaceHelper.replaceFunction((Function) expression, fieldNameMap, exactReplace);
|
||||
replaceService.replaceFunction((Function) expression, fieldNameMap, exactReplace);
|
||||
}
|
||||
super.visit(orderBy);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.Alias;
|
||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -12,53 +15,58 @@ import java.util.Objects;
|
||||
public class QueryExpressionReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
private Map<String, String> fieldExprMap;
|
||||
private String lastColumnName;
|
||||
|
||||
public QueryExpressionReplaceVisitor(Map<String, String> fieldExprMap) {
|
||||
this.fieldExprMap = fieldExprMap;
|
||||
}
|
||||
|
||||
protected void visitBinaryExpression(BinaryExpression expr) {
|
||||
expr.setLeftExpression(replace(expr.getLeftExpression(), fieldExprMap));
|
||||
expr.setRightExpression(replace(expr.getRightExpression(), fieldExprMap));
|
||||
Expression left = expr.getLeftExpression();
|
||||
String toReplace = "";
|
||||
if (left instanceof Function) {
|
||||
Function leftFunc = (Function) left;
|
||||
if (leftFunc.getParameters().getExpressions().get(0) instanceof Column) {
|
||||
toReplace = getReplaceExpr(leftFunc, fieldExprMap);
|
||||
}
|
||||
}
|
||||
if (left instanceof Column) {
|
||||
toReplace = getReplaceExpr((Column) left, fieldExprMap);
|
||||
}
|
||||
if (!toReplace.isEmpty()) {
|
||||
Expression expression = getExpression(toReplace);
|
||||
if (Objects.nonNull(expression)) {
|
||||
expr.setLeftExpression(expression);
|
||||
return;
|
||||
}
|
||||
}
|
||||
expr.getLeftExpression().accept(this);
|
||||
expr.getRightExpression().accept(this);
|
||||
}
|
||||
|
||||
public void visit(SelectItem selectExpressionItem) {
|
||||
|
||||
Expression expression = selectExpressionItem.getExpression();
|
||||
String toReplace = "";
|
||||
String columnName = "";
|
||||
if (expression instanceof Function) {
|
||||
Function leftFunc = (Function) expression;
|
||||
if (Objects.nonNull(leftFunc.getParameters())
|
||||
&& leftFunc.getParameters().getExpressions().get(0) instanceof Column) {
|
||||
if (leftFunc.getParameters().getExpressions().get(0) instanceof Column) {
|
||||
Column column = (Column) leftFunc.getParameters().getExpressions().get(0);
|
||||
lastColumnName = column.getColumnName();
|
||||
columnName = column.getColumnName();
|
||||
toReplace = getReplaceExpr(leftFunc, fieldExprMap);
|
||||
}
|
||||
} else if (expression instanceof Column) {
|
||||
}
|
||||
if (expression instanceof Column) {
|
||||
Column column = (Column) expression;
|
||||
lastColumnName = column.getColumnName();
|
||||
columnName = column.getColumnName();
|
||||
toReplace = getReplaceExpr((Column) expression, fieldExprMap);
|
||||
} else if (expression instanceof BinaryExpression) {
|
||||
BinaryExpression expr = (BinaryExpression) expression;
|
||||
expr.setLeftExpression(replace(expr.getLeftExpression(), fieldExprMap));
|
||||
expr.setRightExpression(replace(expr.getRightExpression(), fieldExprMap));
|
||||
}
|
||||
|
||||
if (expression instanceof BinaryExpression) {
|
||||
BinaryExpression binaryExpression = (BinaryExpression) expression;
|
||||
visitBinaryExpression(binaryExpression);
|
||||
}
|
||||
|
||||
if (expression instanceof Parenthesis) {
|
||||
replace(expression, fieldExprMap);
|
||||
}
|
||||
|
||||
if (!toReplace.isEmpty()) {
|
||||
Expression toReplaceExpr = getExpression(toReplace);
|
||||
if (Objects.nonNull(toReplaceExpr)) {
|
||||
selectExpressionItem.setExpression(toReplaceExpr);
|
||||
if (Objects.isNull(selectExpressionItem.getAlias())) {
|
||||
selectExpressionItem.setAlias(new Alias(lastColumnName, true));
|
||||
selectExpressionItem.setAlias(new Alias(columnName, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,26 +75,11 @@ public class QueryExpressionReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
public static Expression replace(Expression expression, Map<String, String> fieldExprMap) {
|
||||
String toReplace = "";
|
||||
if (expression instanceof Function) {
|
||||
Function function = (Function) expression;
|
||||
if (function.getParameters().getExpressions().get(0) instanceof Column) {
|
||||
toReplace = getReplaceExpr((Function) expression, fieldExprMap);
|
||||
}
|
||||
toReplace = getReplaceExpr((Function) expression, fieldExprMap);
|
||||
}
|
||||
if (expression instanceof Column) {
|
||||
toReplace = getReplaceExpr((Column) expression, fieldExprMap);
|
||||
}
|
||||
if (expression instanceof BinaryExpression) {
|
||||
BinaryExpression binaryExpression = (BinaryExpression) expression;
|
||||
binaryExpression
|
||||
.setLeftExpression(replace(binaryExpression.getLeftExpression(), fieldExprMap));
|
||||
binaryExpression.setRightExpression(
|
||||
replace(binaryExpression.getRightExpression(), fieldExprMap));
|
||||
}
|
||||
if (expression instanceof Parenthesis) {
|
||||
Parenthesis parenthesis = (Parenthesis) expression;
|
||||
parenthesis.setExpression(replace(parenthesis.getExpression(), fieldExprMap));
|
||||
}
|
||||
|
||||
if (!toReplace.isEmpty()) {
|
||||
Expression replace = getExpression(toReplace);
|
||||
if (Objects.nonNull(replace)) {
|
||||
@@ -116,16 +109,6 @@ public class QueryExpressionReplaceVisitor extends ExpressionVisitorAdapter {
|
||||
|
||||
public static String getReplaceExpr(Function function, Map<String, String> fieldExprMap) {
|
||||
Column column = (Column) function.getParameters().getExpressions().get(0);
|
||||
String expr = getReplaceExpr(column, fieldExprMap);
|
||||
// if metric expr itself has agg function then replace original function in the SQL
|
||||
if (StringUtils.isBlank(expr)) {
|
||||
return expr;
|
||||
} else if (!SqlSelectFunctionHelper.getAggregateFunctions(expr).isEmpty()) {
|
||||
return expr;
|
||||
} else {
|
||||
String col = getReplaceExpr(column, fieldExprMap);
|
||||
column.setColumnName(col);
|
||||
return function.toString();
|
||||
}
|
||||
return getReplaceExpr(column, fieldExprMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.util.EditDistanceUtils;
|
||||
import com.tencent.supersonic.common.util.StringUtil;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Data
|
||||
public class ReplaceService {
|
||||
|
||||
@Value("${s2.replace.threshold:0.4}")
|
||||
private double replaceColumnThreshold;
|
||||
|
||||
public void replaceFunction(Function expression, Map<String, String> fieldNameMap,
|
||||
boolean exactReplace) {
|
||||
Function function = expression;
|
||||
ExpressionList<?> expressions = function.getParameters();
|
||||
for (Expression column : expressions) {
|
||||
if (column instanceof Column) {
|
||||
replaceColumn((Column) column, fieldNameMap, exactReplace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceColumn(Column column, Map<String, String> fieldNameMap,
|
||||
boolean exactReplace) {
|
||||
String columnName = StringUtil.replaceBackticks(column.getColumnName());
|
||||
String replaceColumn = getReplaceValue(columnName, fieldNameMap, exactReplace);
|
||||
if (StringUtils.isNotBlank(replaceColumn)) {
|
||||
column.setColumnName(replaceColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public String getReplaceValue(String beforeValue, Map<String, String> valueMap,
|
||||
boolean exactReplace) {
|
||||
String replaceValue = valueMap.get(beforeValue);
|
||||
if (StringUtils.isNotBlank(replaceValue)) {
|
||||
return replaceValue;
|
||||
}
|
||||
if (exactReplace) {
|
||||
return null;
|
||||
}
|
||||
Optional<Entry<String, String>> first = valueMap.entrySet().stream().sorted((k1, k2) -> {
|
||||
String k1Value = k1.getKey();
|
||||
String k2Value = k2.getKey();
|
||||
Double k1Similarity = EditDistanceUtils.getSimilarity(beforeValue, k1Value);
|
||||
Double k2Similarity = EditDistanceUtils.getSimilarity(beforeValue, k2Value);
|
||||
return k2Similarity.compareTo(k1Similarity);
|
||||
}).collect(Collectors.toList()).stream().findFirst();
|
||||
|
||||
if (first.isPresent()) {
|
||||
replaceValue = first.get().getValue();
|
||||
double similarity = EditDistanceUtils.getSimilarity(beforeValue, replaceValue);
|
||||
if (similarity > replaceColumnThreshold) {
|
||||
return replaceValue;
|
||||
}
|
||||
}
|
||||
return beforeValue;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,35 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Function;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import net.sf.jsqlparser.expression.Parenthesis;
|
||||
import net.sf.jsqlparser.expression.StringValue;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.select.GroupByElement;
|
||||
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.Select;
|
||||
import net.sf.jsqlparser.statement.select.SelectItem;
|
||||
import net.sf.jsqlparser.statement.select.SelectVisitorAdapter;
|
||||
import net.sf.jsqlparser.statement.select.SetOperationList;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/** Sql Parser add Helper */
|
||||
@Slf4j
|
||||
@@ -126,7 +144,42 @@ public class SqlAddHelper {
|
||||
return sql;
|
||||
}
|
||||
PlainSelect plainSelect = (PlainSelect) selectStatement;
|
||||
|
||||
List<String> chNameList = TimeDimensionEnum.getChNameList();
|
||||
Boolean dateWhere = false;
|
||||
for (String chName : chNameList) {
|
||||
if (expression.toString().contains(chName)) {
|
||||
dateWhere = true;
|
||||
}
|
||||
}
|
||||
List<PlainSelect> plainSelectList = SqlSelectHelper.getWithItem(selectStatement);
|
||||
if (!CollectionUtils.isEmpty(plainSelectList) && dateWhere) {
|
||||
List<String> withNameList = SqlSelectHelper.getWithName(sql);
|
||||
for (int i = 0; i < plainSelectList.size(); i++) {
|
||||
if (plainSelectList.get(i).getFromItem() instanceof Table) {
|
||||
Table table = (Table) plainSelectList.get(i).getFromItem();
|
||||
if (withNameList.contains(table.getName())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Set<String> result = new HashSet<>();
|
||||
List<PlainSelect> subPlainSelectList = new ArrayList<>();
|
||||
subPlainSelectList.add(plainSelectList.get(i));
|
||||
SqlSelectHelper.getWhereFields(subPlainSelectList, result);
|
||||
if (TimeDimensionEnum.containsZhTimeDimension(new ArrayList<>(result))) {
|
||||
continue;
|
||||
}
|
||||
Expression subWhere = plainSelectList.get(i).getWhere();
|
||||
addWhere(plainSelectList.get(i), subWhere, expression);
|
||||
}
|
||||
return selectStatement.toString();
|
||||
}
|
||||
if (plainSelect.getFromItem() instanceof ParenthesedSelect && dateWhere) {
|
||||
ParenthesedSelect parenthesedSelect = (ParenthesedSelect) plainSelect.getFromItem();
|
||||
PlainSelect subPlainSelect = parenthesedSelect.getPlainSelect();
|
||||
Expression subWhere = subPlainSelect.getWhere();
|
||||
addWhere(subPlainSelect, subWhere, expression);
|
||||
return selectStatement.toString();
|
||||
}
|
||||
Expression where = plainSelect.getWhere();
|
||||
|
||||
addWhere(plainSelect, where, expression);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.statement.select.PlainSelect;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.Objects;
|
||||
@Slf4j
|
||||
public class SqlDateSelectHelper {
|
||||
|
||||
public static DateVisitor.DateBoundInfo getDateBoundInfo(String sql, String dateField) {
|
||||
public static DateVisitor.DateBoundInfo getDateBoundInfo(String sql) {
|
||||
List<PlainSelect> plainSelectList = SqlSelectHelper.getPlainSelect(sql);
|
||||
if (plainSelectList.size() != 1) {
|
||||
return null;
|
||||
@@ -25,7 +25,7 @@ public class SqlDateSelectHelper {
|
||||
if (Objects.isNull(where)) {
|
||||
return null;
|
||||
}
|
||||
DateVisitor dateVisitor = new DateVisitor(Collections.singletonList(dateField));
|
||||
DateVisitor dateVisitor = new DateVisitor(TimeDimensionEnum.getChNameList());
|
||||
where.accept(dateVisitor);
|
||||
return dateVisitor.getDateBoundInfo();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,16 @@ import net.sf.jsqlparser.expression.LongValue;
|
||||
import net.sf.jsqlparser.expression.Parenthesis;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ComparisonOperator;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
|
||||
import net.sf.jsqlparser.expression.operators.relational.InExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
|
||||
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.AllColumns;
|
||||
@@ -174,8 +183,6 @@ public class SqlRemoveHelper {
|
||||
handleInExpression((InExpression) expression, removeFieldNames);
|
||||
} else if (expression instanceof LikeExpression) {
|
||||
handleLikeExpression((LikeExpression) expression, removeFieldNames);
|
||||
} else if (expression instanceof Between) {
|
||||
handleBetweenExpression((Between) expression, removeFieldNames);
|
||||
}
|
||||
} catch (JSQLParserException e) {
|
||||
log.error("JSQLParserException", e);
|
||||
@@ -219,17 +226,6 @@ public class SqlRemoveHelper {
|
||||
updateLikeExpression(likeExpression, constantExpression);
|
||||
}
|
||||
|
||||
private static void handleBetweenExpression(Between between, Set<String> removeFieldNames)
|
||||
throws JSQLParserException {
|
||||
String columnName = SqlSelectHelper.getColumnName(between.getLeftExpression());
|
||||
if (!removeFieldNames.contains(columnName)) {
|
||||
return;
|
||||
}
|
||||
Between constantExpression =
|
||||
(Between) CCJSqlParserUtil.parseCondExpression(JsqlConstants.BETWEEN_AND_CONSTANT);
|
||||
updateBetweenExpression(between, constantExpression);
|
||||
}
|
||||
|
||||
private static void updateComparisonOperator(ComparisonOperator original,
|
||||
ComparisonOperator constantExpression) {
|
||||
original.setLeftExpression(constantExpression.getLeftExpression());
|
||||
@@ -249,12 +245,6 @@ public class SqlRemoveHelper {
|
||||
original.setRightExpression(constantExpression.getRightExpression());
|
||||
}
|
||||
|
||||
private static void updateBetweenExpression(Between between, Between constantExpression) {
|
||||
between.setBetweenExpressionEnd(constantExpression.getBetweenExpressionEnd());
|
||||
between.setBetweenExpressionStart(constantExpression.getBetweenExpressionStart());
|
||||
between.setLeftExpression(constantExpression.getLeftExpression());
|
||||
}
|
||||
|
||||
public static String removeHavingCondition(String sql, Set<String> removeFieldNames) {
|
||||
Select selectStatement = SqlSelectHelper.getSelect(sql);
|
||||
if (!(selectStatement instanceof PlainSelect)) {
|
||||
@@ -383,10 +373,6 @@ public class SqlRemoveHelper {
|
||||
LikeExpression likeExpression = (LikeExpression) expression;
|
||||
Expression leftExpression = likeExpression.getLeftExpression();
|
||||
return recursionBase(leftExpression, expression, sqlEditEnum);
|
||||
} else if (expression instanceof Between) {
|
||||
Between between = (Between) expression;
|
||||
Expression leftExpression = between.getLeftExpression();
|
||||
return recursionBase(leftExpression, expression, sqlEditEnum);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum;
|
||||
import com.tencent.supersonic.common.util.EditDistanceUtils;
|
||||
import com.tencent.supersonic.common.util.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
@@ -26,22 +25,21 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Sql Parser replace Helper
|
||||
*/
|
||||
@Slf4j
|
||||
public class SqlReplaceHelper {
|
||||
|
||||
private final static double replaceColumnThreshold = 0.4;
|
||||
|
||||
public static String escapeTableName(String table) {
|
||||
return String.format("`%s`", table);
|
||||
}
|
||||
|
||||
public static String replaceAggFields(String sql,
|
||||
Map<String, Pair<String, String>> fieldNameToAggMap) {
|
||||
Select selectStatement = SqlSelectHelper.getSelect(sql);
|
||||
@@ -231,26 +229,6 @@ public class SqlReplaceHelper {
|
||||
orderByElement.accept(new OrderByReplaceVisitor(fieldNameMap, exactReplace));
|
||||
}
|
||||
}
|
||||
List<Select> selects = operationList.getSelects();
|
||||
if (!CollectionUtils.isEmpty(selects)) {
|
||||
for (Select select : selects) {
|
||||
if (select instanceof PlainSelect) {
|
||||
replaceFieldsInPlainOneSelect(fieldNameMap, exactReplace, (PlainSelect) select);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<WithItem> withItems = operationList.getWithItemsList();
|
||||
if (!CollectionUtils.isEmpty(withItems)) {
|
||||
for (WithItem withItem : withItems) {
|
||||
Select select = withItem.getSelect();
|
||||
if (select instanceof PlainSelect) {
|
||||
replaceFieldsInPlainOneSelect(fieldNameMap, exactReplace, (PlainSelect) select);
|
||||
} else if (select instanceof ParenthesedSelect) {
|
||||
replaceFieldsInPlainOneSelect(fieldNameMap, exactReplace,
|
||||
select.getPlainSelect());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String replaceFunction(String sql, Map<String, String> functionMap) {
|
||||
@@ -425,10 +403,8 @@ public class SqlReplaceHelper {
|
||||
painSelect.accept(new SelectVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(PlainSelect plainSelect) {
|
||||
if (Objects.nonNull(plainSelect.getFromItem())) {
|
||||
plainSelect.getFromItem().accept(new TableNameReplaceVisitor(tableName,
|
||||
new HashSet<>(withNameList)));
|
||||
}
|
||||
plainSelect.getFromItem().accept(
|
||||
new TableNameReplaceVisitor(tableName, new HashSet<>(withNameList)));
|
||||
}
|
||||
});
|
||||
replaceJoins(painSelect, tableName, withNameList);
|
||||
@@ -473,69 +449,6 @@ public class SqlReplaceHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static String replaceAliasFieldName(String sql, Map<String, String> fieldNameMap) {
|
||||
Select selectStatement = SqlSelectHelper.getSelect(sql);
|
||||
if (!(selectStatement instanceof PlainSelect)) {
|
||||
return sql;
|
||||
}
|
||||
PlainSelect plainSelect = (PlainSelect) selectStatement;
|
||||
FieldAliasReplaceNameVisitor visitor = new FieldAliasReplaceNameVisitor(fieldNameMap);
|
||||
for (SelectItem selectItem : plainSelect.getSelectItems()) {
|
||||
selectItem.accept(visitor);
|
||||
}
|
||||
Map<String, String> aliasToActualExpression = visitor.getAliasToActualExpression();
|
||||
if (Objects.nonNull(aliasToActualExpression) && !aliasToActualExpression.isEmpty()) {
|
||||
return replaceFields(selectStatement.toString(), aliasToActualExpression, true);
|
||||
}
|
||||
return selectStatement.toString();
|
||||
}
|
||||
|
||||
public static String replaceAliasWithBackticks(String sql) {
|
||||
Select selectStatement = SqlSelectHelper.getSelect(sql);
|
||||
if (!(selectStatement instanceof PlainSelect)) {
|
||||
return sql;
|
||||
}
|
||||
PlainSelect plainSelect = (PlainSelect) selectStatement;
|
||||
FieldAliasReplaceWithBackticksVisitor visitor = new FieldAliasReplaceWithBackticksVisitor();
|
||||
for (SelectItem selectItem : plainSelect.getSelectItems()) {
|
||||
selectItem.accept(visitor);
|
||||
}
|
||||
// Replace `order by` and `group by`
|
||||
// Get the map of field aliases that have been replaced
|
||||
Map<String, String> aliasReplacedMap = visitor.getFieldAliasReplacedMap();
|
||||
|
||||
// If no aliases have been replaced, return the original SQL statement as a string
|
||||
if (aliasReplacedMap.isEmpty()) {
|
||||
return selectStatement.toString();
|
||||
}
|
||||
// Order by elements
|
||||
List<OrderByElement> orderByElements = selectStatement.getOrderByElements();
|
||||
if (!CollectionUtils.isEmpty(orderByElements)) {
|
||||
for (OrderByElement orderByElement : orderByElements) {
|
||||
orderByElement.accept(new OrderByReplaceVisitor(aliasReplacedMap, true));
|
||||
}
|
||||
}
|
||||
// Group by elements
|
||||
GroupByElement groupByElement = plainSelect.getGroupBy();
|
||||
if (Objects.nonNull(groupByElement)) {
|
||||
groupByElement.accept(new GroupByReplaceVisitor(aliasReplacedMap, true));
|
||||
}
|
||||
// Alias columns
|
||||
for (SelectItem<?> selectItem : plainSelect.getSelectItems()) {
|
||||
if (selectItem.getExpression() instanceof Column) {
|
||||
replaceColumn((Column) selectItem.getExpression(), aliasReplacedMap, true);
|
||||
}
|
||||
}
|
||||
// Having
|
||||
Expression having = plainSelect.getHaving();
|
||||
if (Objects.nonNull(having)) {
|
||||
ExpressionReplaceVisitor expressionReplaceVisitor =
|
||||
new ExpressionReplaceVisitor(aliasReplacedMap);
|
||||
having.accept(expressionReplaceVisitor);
|
||||
}
|
||||
return selectStatement.toString();
|
||||
}
|
||||
|
||||
public static String replaceAlias(String sql) {
|
||||
Select selectStatement = SqlSelectHelper.getSelect(sql);
|
||||
if (!(selectStatement instanceof PlainSelect)) {
|
||||
@@ -677,17 +590,10 @@ public class SqlReplaceHelper {
|
||||
return expr;
|
||||
}
|
||||
|
||||
public static String replaceSqlByExpression(String tableName, String sql,
|
||||
Map<String, String> replace) {
|
||||
public static String replaceSqlByExpression(String sql, Map<String, String> replace) {
|
||||
Select selectStatement = SqlSelectHelper.getSelect(sql);
|
||||
List<PlainSelect> plainSelectList = new ArrayList<>();
|
||||
if (selectStatement instanceof PlainSelect) {
|
||||
// if with statement exists, replace expression in the with statement.
|
||||
if (!CollectionUtils.isEmpty(selectStatement.getWithItemsList())) {
|
||||
selectStatement.getWithItemsList().forEach(withItem -> {
|
||||
plainSelectList.add(withItem.getSelect().getPlainSelect());
|
||||
});
|
||||
}
|
||||
plainSelectList.add((PlainSelect) selectStatement);
|
||||
} else if (selectStatement instanceof SetOperationList) {
|
||||
SetOperationList setOperationList = (SetOperationList) selectStatement;
|
||||
@@ -697,40 +603,12 @@ public class SqlReplaceHelper {
|
||||
plainSelectList.add(subPlainSelect);
|
||||
});
|
||||
}
|
||||
List<Select> selects = setOperationList.getSelects();
|
||||
if (!CollectionUtils.isEmpty(selects)) {
|
||||
for (Select select : selects) {
|
||||
if (select instanceof PlainSelect) {
|
||||
plainSelectList.add((PlainSelect) select);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<WithItem> withItems = setOperationList.getWithItemsList();
|
||||
if (!CollectionUtils.isEmpty(withItems)) {
|
||||
for (WithItem withItem : withItems) {
|
||||
Select select = withItem.getSelect();
|
||||
if (select instanceof PlainSelect) {
|
||||
plainSelectList.add((PlainSelect) select);
|
||||
} else if (select instanceof ParenthesedSelect) {
|
||||
plainSelectList.add(select.getPlainSelect());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return sql;
|
||||
}
|
||||
|
||||
List<PlainSelect> plainSelects = SqlSelectHelper.getPlainSelects(plainSelectList);
|
||||
for (PlainSelect plainSelect : plainSelects) {
|
||||
if (Objects.nonNull(plainSelect.getFromItem())) {
|
||||
Table table = (Table) plainSelect.getFromItem();
|
||||
if (table.getName().equals(tableName)) {
|
||||
replacePlainSelectByExpr(plainSelect, replace);
|
||||
if (SqlSelectHelper.hasAggregateFunction(plainSelect)) {
|
||||
SqlSelectHelper.addMissingGroupby(plainSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
replacePlainSelectByExpr(plainSelect, replace);
|
||||
}
|
||||
return selectStatement.toString();
|
||||
}
|
||||
@@ -817,54 +695,4 @@ public class SqlReplaceHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceFunction(Function expression, Map<String, String> fieldNameMap,
|
||||
boolean exactReplace) {
|
||||
Function function = expression;
|
||||
ExpressionList<?> expressions = function.getParameters();
|
||||
for (Expression column : expressions) {
|
||||
if (column instanceof Column) {
|
||||
replaceColumn((Column) column, fieldNameMap, exactReplace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceColumn(Column column, Map<String, String> fieldNameMap,
|
||||
boolean exactReplace) {
|
||||
String columnName = StringUtil.replaceBackticks(column.getColumnName());
|
||||
String replaceColumn = getReplaceValue(columnName, fieldNameMap, exactReplace);
|
||||
if (StringUtils.isNotBlank(replaceColumn)) {
|
||||
log.debug("Replaced column {} to {}", column.getColumnName(), replaceColumn);
|
||||
column.setColumnName(replaceColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getReplaceValue(String beforeValue, Map<String, String> valueMap,
|
||||
boolean exactReplace) {
|
||||
String replaceValue = valueMap.get(beforeValue);
|
||||
if (StringUtils.isNotBlank(replaceValue)) {
|
||||
return replaceValue;
|
||||
}
|
||||
if (exactReplace) {
|
||||
return null;
|
||||
}
|
||||
Optional<Map.Entry<String, String>> first =
|
||||
valueMap.entrySet().stream().sorted((k1, k2) -> {
|
||||
String k1Value = k1.getKey();
|
||||
String k2Value = k2.getKey();
|
||||
Double k1Similarity = EditDistanceUtils.getSimilarity(beforeValue, k1Value);
|
||||
Double k2Similarity = EditDistanceUtils.getSimilarity(beforeValue, k2Value);
|
||||
return k2Similarity.compareTo(k1Similarity);
|
||||
}).collect(Collectors.toList()).stream().findFirst();
|
||||
|
||||
if (first.isPresent()) {
|
||||
replaceValue = first.get().getValue();
|
||||
double similarity = EditDistanceUtils.getSimilarity(beforeValue, replaceValue);
|
||||
if (similarity > replaceColumnThreshold) {
|
||||
return replaceValue;
|
||||
}
|
||||
}
|
||||
return beforeValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.tencent.supersonic.common.util.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
@@ -135,24 +133,6 @@ public class SqlSelectHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Set<String> getAliasFields(PlainSelect plainSelect) {
|
||||
Set<String> result = new HashSet<>();
|
||||
List<SelectItem<?>> selectItems = plainSelect.getSelectItems();
|
||||
for (SelectItem selectItem : selectItems) {
|
||||
selectItem.accept(new AliasAcquireVisitor(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Set<String> getAliasFields(String sql) {
|
||||
List<PlainSelect> plainSelects = getPlainSelects(getPlainSelect(sql));
|
||||
Set<String> aliasFields = new HashSet<>();
|
||||
plainSelects.forEach(select -> {
|
||||
aliasFields.addAll(getAliasFields(select));
|
||||
});
|
||||
return aliasFields;
|
||||
}
|
||||
|
||||
public static List<PlainSelect> getPlainSelect(Select selectStatement) {
|
||||
if (selectStatement == null) {
|
||||
return null;
|
||||
@@ -228,7 +208,7 @@ public class SqlSelectHelper {
|
||||
statement = CCJSqlParserUtil.parse(sql);
|
||||
} catch (JSQLParserException e) {
|
||||
log.error("parse error, sql:{}", sql, e);
|
||||
throw new RuntimeException(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (statement instanceof ParenthesedSelect) {
|
||||
@@ -284,18 +264,11 @@ public class SqlSelectHelper {
|
||||
public static List<String> getAllSelectFields(String sql) {
|
||||
List<PlainSelect> plainSelects = getPlainSelects(getPlainSelect(sql));
|
||||
Set<String> results = new HashSet<>();
|
||||
Set<String> aliases = new HashSet<>();
|
||||
for (PlainSelect plainSelect : plainSelects) {
|
||||
List<String> fields = getFieldsByPlainSelect(plainSelect);
|
||||
Set<String> subaliases = getAliasFields(plainSelect);
|
||||
subaliases.removeAll(fields);
|
||||
results.addAll(fields);
|
||||
aliases.addAll(subaliases);
|
||||
}
|
||||
// do not account in aliases
|
||||
results.removeAll(aliases);
|
||||
return new ArrayList<>(
|
||||
results.stream().map(r -> r.replaceAll("`", "")).collect(Collectors.toList()));
|
||||
return new ArrayList<>(results);
|
||||
}
|
||||
|
||||
private static List<String> getFieldsByPlainSelect(PlainSelect plainSelect) {
|
||||
@@ -304,37 +277,19 @@ public class SqlSelectHelper {
|
||||
}
|
||||
List<PlainSelect> plainSelectList = new ArrayList<>();
|
||||
plainSelectList.add(plainSelect);
|
||||
Set<String> selectFields = getSelectFields(plainSelectList);
|
||||
Set<String> aliases = getAliasFields(plainSelect);
|
||||
Set<String> result = getSelectFields(plainSelectList);
|
||||
|
||||
Set<String> groupByFields = Sets.newHashSet();
|
||||
getGroupByFields(plainSelect, groupByFields);
|
||||
groupByFields.removeAll(aliases);
|
||||
getGroupByFields(plainSelect, result);
|
||||
|
||||
Set<String> orderByFields = Sets.newHashSet();
|
||||
getOrderByFields(plainSelect, orderByFields);
|
||||
orderByFields.removeAll(aliases);
|
||||
getOrderByFields(plainSelect, result);
|
||||
|
||||
Set<String> whereFields = Sets.newHashSet();
|
||||
getWhereFields(plainSelectList, whereFields);
|
||||
whereFields.removeAll(aliases);
|
||||
getWhereFields(plainSelectList, result);
|
||||
|
||||
Set<String> havingFields = Sets.newHashSet();
|
||||
getHavingFields(plainSelect, havingFields);
|
||||
havingFields.removeAll(aliases);
|
||||
getHavingFields(plainSelect, result);
|
||||
|
||||
Set<String> lateralFields = Sets.newHashSet();
|
||||
getLateralViewsFields(plainSelect, lateralFields);
|
||||
lateralFields.removeAll(aliases);
|
||||
getLateralViewsFields(plainSelect, result);
|
||||
|
||||
List<String> results = Lists.newArrayList();
|
||||
results.addAll(selectFields);
|
||||
results.addAll(groupByFields);
|
||||
results.addAll(orderByFields);
|
||||
results.addAll(whereFields);
|
||||
results.addAll(havingFields);
|
||||
results.addAll(lateralFields);
|
||||
return new ArrayList<>(results);
|
||||
return new ArrayList<>(result);
|
||||
}
|
||||
|
||||
private static void getHavingFields(PlainSelect plainSelect, Set<String> result) {
|
||||
@@ -460,9 +415,6 @@ public class SqlSelectHelper {
|
||||
.map(fieldExpression -> fieldExpression.getFieldName()).filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
result.addAll(collect);
|
||||
|
||||
Set<String> aliases = getAliasFields(plainSelect);
|
||||
result.removeAll(aliases);
|
||||
}
|
||||
|
||||
public static List<FieldExpression> getOrderByExpressions(String sql) {
|
||||
@@ -667,9 +619,8 @@ public class SqlSelectHelper {
|
||||
}
|
||||
if (withSelect instanceof ParenthesedSelect) {
|
||||
ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withSelect;
|
||||
List<PlainSelect> plainSelects = new ArrayList<>();
|
||||
SqlReplaceHelper.getFromSelect(parenthesedSelect, plainSelects);
|
||||
plainSelectList.addAll(plainSelects);
|
||||
PlainSelect withPlainSelect = parenthesedSelect.getPlainSelect();
|
||||
plainSelectList.add(withPlainSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -728,61 +679,61 @@ public class SqlSelectHelper {
|
||||
return table.getFullyQualifiedName();
|
||||
}
|
||||
|
||||
public static Set<String> getFieldsFromExpr(String expr) {
|
||||
public static Set<String> getColumnFromExpr(String expr) {
|
||||
Expression expression = QueryExpressionReplaceVisitor.getExpression(expr);
|
||||
Set<String> columns = new HashSet<>();
|
||||
if (Objects.nonNull(expression)) {
|
||||
getFieldsFromExpr(expression, columns);
|
||||
getColumnFromExpr(expression, columns);
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
public static void getFieldsFromExpr(Expression expression, Set<String> columns) {
|
||||
public static void getColumnFromExpr(Expression expression, Set<String> columns) {
|
||||
if (expression instanceof Column) {
|
||||
columns.add(((Column) expression).getColumnName());
|
||||
}
|
||||
if (expression instanceof Function) {
|
||||
ExpressionList<?> expressionList = ((Function) expression).getParameters();
|
||||
for (Expression expr : expressionList) {
|
||||
getFieldsFromExpr(expr, columns);
|
||||
getColumnFromExpr(expr, columns);
|
||||
}
|
||||
}
|
||||
if (expression instanceof CaseExpression) {
|
||||
CaseExpression expr = (CaseExpression) expression;
|
||||
if (Objects.nonNull(expr.getWhenClauses())) {
|
||||
for (WhenClause whenClause : expr.getWhenClauses()) {
|
||||
getFieldsFromExpr(whenClause.getWhenExpression(), columns);
|
||||
getFieldsFromExpr(whenClause.getThenExpression(), columns);
|
||||
getColumnFromExpr(whenClause.getWhenExpression(), columns);
|
||||
getColumnFromExpr(whenClause.getThenExpression(), columns);
|
||||
}
|
||||
}
|
||||
if (Objects.nonNull(expr.getElseExpression())) {
|
||||
getFieldsFromExpr(expr.getElseExpression(), columns);
|
||||
getColumnFromExpr(expr.getElseExpression(), columns);
|
||||
}
|
||||
}
|
||||
if (expression instanceof BinaryExpression) {
|
||||
BinaryExpression expr = (BinaryExpression) expression;
|
||||
getFieldsFromExpr(expr.getLeftExpression(), columns);
|
||||
getFieldsFromExpr(expr.getRightExpression(), columns);
|
||||
getColumnFromExpr(expr.getLeftExpression(), columns);
|
||||
getColumnFromExpr(expr.getRightExpression(), columns);
|
||||
}
|
||||
if (expression instanceof InExpression) {
|
||||
InExpression inExpression = (InExpression) expression;
|
||||
getFieldsFromExpr(inExpression.getLeftExpression(), columns);
|
||||
getColumnFromExpr(inExpression.getLeftExpression(), columns);
|
||||
}
|
||||
if (expression instanceof Between) {
|
||||
Between between = (Between) expression;
|
||||
getFieldsFromExpr(between.getLeftExpression(), columns);
|
||||
getColumnFromExpr(between.getLeftExpression(), columns);
|
||||
}
|
||||
if (expression instanceof IsBooleanExpression) {
|
||||
IsBooleanExpression isBooleanExpression = (IsBooleanExpression) expression;
|
||||
getFieldsFromExpr(isBooleanExpression.getLeftExpression(), columns);
|
||||
getColumnFromExpr(isBooleanExpression.getLeftExpression(), columns);
|
||||
}
|
||||
if (expression instanceof IsNullExpression) {
|
||||
IsNullExpression isNullExpression = (IsNullExpression) expression;
|
||||
getFieldsFromExpr(isNullExpression.getLeftExpression(), columns);
|
||||
getColumnFromExpr(isNullExpression.getLeftExpression(), columns);
|
||||
}
|
||||
if (expression instanceof Parenthesis) {
|
||||
Parenthesis expr = (Parenthesis) expression;
|
||||
getFieldsFromExpr(expr.getExpression(), columns);
|
||||
getColumnFromExpr(expr.getExpression(), columns);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,9 +846,7 @@ public class SqlSelectHelper {
|
||||
collectSelects(withItem.getSelect(), selects);
|
||||
} else if (select instanceof ParenthesedSelect) {
|
||||
ParenthesedSelect parenthesedSelect = (ParenthesedSelect) select;
|
||||
List<PlainSelect> plainSelects = new ArrayList<>();
|
||||
SqlReplaceHelper.getFromSelect(parenthesedSelect, plainSelects);
|
||||
plainSelects.forEach(s -> collectSelects(s, selects));
|
||||
collectSelects(parenthesedSelect.getPlainSelect(), selects);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,31 +914,4 @@ public class SqlSelectHelper {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void addMissingGroupby(PlainSelect plainSelect) {
|
||||
if (Objects.nonNull(plainSelect.getGroupBy())
|
||||
&& !plainSelect.getGroupBy().getGroupByExpressionList().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
GroupByElement groupBy = new GroupByElement();
|
||||
for (SelectItem selectItem : plainSelect.getSelectItems()) {
|
||||
Expression expression = selectItem.getExpression();
|
||||
if (expression instanceof Column) {
|
||||
groupBy.addGroupByExpression(expression);
|
||||
}
|
||||
}
|
||||
if (!groupBy.getGroupByExpressionList().isEmpty()) {
|
||||
plainSelect.setGroupByElement(groupBy);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasAggregateFunction(PlainSelect plainSelect) {
|
||||
List<SelectItem<?>> selectItems = plainSelect.getSelectItems();
|
||||
FunctionVisitor visitor = new FunctionVisitor();
|
||||
for (SelectItem selectItem : selectItems) {
|
||||
selectItem.accept(visitor);
|
||||
}
|
||||
return !visitor.getFunctionNames().isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class ChatModelConfig implements Serializable {
|
||||
private String baseUrl;
|
||||
private String apiKey;
|
||||
private String modelName;
|
||||
private String apiVersion;
|
||||
private Double temperature = 0.0d;
|
||||
private Long timeOut = 60L;
|
||||
private String endpoint;
|
||||
|
||||
@@ -34,9 +34,6 @@ public class ChatModelParameters {
|
||||
public static final Parameter CHAT_MODEL_API_KEY = new Parameter("apiKey", "", "ApiKey", "",
|
||||
"password", MODULE_NAME, null, getApiKeyDependency());
|
||||
|
||||
public static final Parameter CHAT_MODEL_API_VERSION = new Parameter("apiVersion", "2024-02-01",
|
||||
"ApiVersion", "", "string", MODULE_NAME, null, getApiVersionDependency());
|
||||
|
||||
public static final Parameter CHAT_MODEL_ENDPOINT = new Parameter("endpoint", "llama_2_70b",
|
||||
"Endpoint", "", "string", MODULE_NAME, null, getEndpointDependency());
|
||||
|
||||
@@ -54,7 +51,7 @@ public class ChatModelParameters {
|
||||
|
||||
public static List<Parameter> getParameters() {
|
||||
return Lists.newArrayList(CHAT_MODEL_PROVIDER, CHAT_MODEL_BASE_URL, CHAT_MODEL_ENDPOINT,
|
||||
CHAT_MODEL_API_KEY, CHAT_MODEL_SECRET_KEY, CHAT_MODEL_NAME, CHAT_MODEL_API_VERSION,
|
||||
CHAT_MODEL_API_KEY, CHAT_MODEL_SECRET_KEY, CHAT_MODEL_NAME,
|
||||
CHAT_MODEL_ENABLE_SEARCH, CHAT_MODEL_TEMPERATURE, CHAT_MODEL_TIMEOUT);
|
||||
}
|
||||
|
||||
@@ -93,12 +90,6 @@ public class ChatModelParameters {
|
||||
ModelProvider.DEMO_CHAT_MODEL.getApiKey()));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getApiVersionDependency() {
|
||||
return getDependency(CHAT_MODEL_PROVIDER.getName(),
|
||||
Lists.newArrayList(OpenAiModelFactory.PROVIDER), ImmutableMap
|
||||
.of(OpenAiModelFactory.PROVIDER, OpenAiModelFactory.DEFAULT_API_VERSION));
|
||||
}
|
||||
|
||||
private static List<Parameter.Dependency> getModelNameDependency() {
|
||||
return getDependency(CHAT_MODEL_PROVIDER.getName(), getCandidateValues(),
|
||||
ImmutableMap.of(OpenAiModelFactory.PROVIDER, OpenAiModelFactory.DEFAULT_MODEL_NAME,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.tencent.supersonic.common.pojo;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.enums.DatePeriodEnum;
|
||||
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
|
||||
import com.tencent.supersonic.common.util.DateUtils;
|
||||
import lombok.Data;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -13,7 +13,7 @@ import java.util.Objects;
|
||||
import static java.time.LocalDate.now;
|
||||
|
||||
@Data
|
||||
public class DateConf implements Serializable {
|
||||
public class DateConf {
|
||||
|
||||
private static final long serialVersionUID = 3074129990945004340L;
|
||||
|
||||
@@ -40,8 +40,6 @@ public class DateConf implements Serializable {
|
||||
|
||||
private boolean groupByDate;
|
||||
|
||||
private String dateField;
|
||||
|
||||
public List<String> getDateList() {
|
||||
if (!CollectionUtils.isEmpty(dateList)) {
|
||||
return dateList;
|
||||
@@ -51,6 +49,18 @@ public class DateConf implements Serializable {
|
||||
return DateUtils.getDateList(startDateStr, endDateStr, getPeriod());
|
||||
}
|
||||
|
||||
public String getGroupByTimeDimension() {
|
||||
if (DatePeriodEnum.DAY.equals(period)) {
|
||||
return TimeDimensionEnum.DAY.getName();
|
||||
} else if (DatePeriodEnum.WEEK.equals(period)) {
|
||||
return TimeDimensionEnum.WEEK.getName();
|
||||
} else if (DatePeriodEnum.MONTH.equals(period)) {
|
||||
return TimeDimensionEnum.MONTH.getName();
|
||||
} else {
|
||||
return TimeDimensionEnum.DAY.getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
@@ -60,15 +70,9 @@ public class DateConf implements Serializable {
|
||||
return false;
|
||||
}
|
||||
DateConf dateConf = (DateConf) o;
|
||||
if (dateMode != dateConf.dateMode) {
|
||||
return false;
|
||||
}
|
||||
if (dateMode == DateMode.RECENT) {
|
||||
return Objects.equals(unit, dateConf.unit) && Objects.equals(period, dateConf.period);
|
||||
} else {
|
||||
return Objects.equals(startDate, dateConf.startDate)
|
||||
&& Objects.equals(endDate, dateConf.endDate);
|
||||
}
|
||||
return dateMode == dateConf.dateMode && Objects.equals(startDate, dateConf.startDate)
|
||||
&& Objects.equals(endDate, dateConf.endDate) && Objects.equals(unit, dateConf.unit)
|
||||
&& Objects.equals(period, dateConf.period);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,13 +3,11 @@ package com.tencent.supersonic.common.pojo;
|
||||
import com.google.common.base.Objects;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
|
||||
import static com.tencent.supersonic.common.pojo.Constants.ASC_UPPER;
|
||||
|
||||
@Data
|
||||
public class Order implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public class Order {
|
||||
|
||||
@NotBlank(message = "Invalid order column")
|
||||
private String column;
|
||||
|
||||
@@ -2,11 +2,8 @@ package com.tencent.supersonic.common.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class PageBaseReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public class PageBaseReq {
|
||||
|
||||
private static final Integer MAX_PAGESIZE = 100;
|
||||
private Integer current = 1;
|
||||
|
||||
@@ -11,36 +11,26 @@ public class QueryColumn {
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private String bizName;
|
||||
private String nameEn;
|
||||
private String showType;
|
||||
private Boolean authorized = true;
|
||||
private String dataFormatType;
|
||||
private DataFormat dataFormat;
|
||||
private String comment;
|
||||
private Long modelId;
|
||||
|
||||
public QueryColumn(String bizName, String type) {
|
||||
public QueryColumn(String nameEn, String type) {
|
||||
this.type = type;
|
||||
this.bizName = bizName;
|
||||
this.nameEn = bizName;
|
||||
this.name = bizName;
|
||||
this.nameEn = nameEn;
|
||||
}
|
||||
|
||||
public QueryColumn(String name, String type, String bizName) {
|
||||
public QueryColumn(String name, String type, String nameEn) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.bizName = bizName;
|
||||
this.nameEn = bizName;
|
||||
this.nameEn = nameEn;
|
||||
this.showType = "CATEGORY";
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type == null ? null : type;
|
||||
}
|
||||
|
||||
public void setBizName(String bizName) {
|
||||
this.bizName = bizName;
|
||||
this.nameEn = bizName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.tencent.supersonic.common.pojo.enums;
|
||||
|
||||
public enum AggOperatorEnum {
|
||||
NONE(""),
|
||||
|
||||
MAX("MAX"),
|
||||
|
||||
MIN("MIN"),
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
package com.tencent.supersonic.common.pojo.enums;
|
||||
|
||||
public enum EngineType {
|
||||
TDW(0, "TDW"),
|
||||
MYSQL(1, "MYSQL"),
|
||||
DORIS(2, "DORIS"),
|
||||
CLICKHOUSE(3, "CLICKHOUSE"),
|
||||
H2(5, "H2"),
|
||||
POSTGRESQL(6, "POSTGRESQL"),
|
||||
OTHER(7, "OTHER"),
|
||||
DUCKDB(8, "DUCKDB"),
|
||||
HANADB(9, "HANADB"),
|
||||
STARROCKS(10, "STARROCKS"),
|
||||
KYUUBI(11, "KYUUBI"),
|
||||
PRESTO(12, "PRESTO"),
|
||||
TRINO(13, "TRINO"),;
|
||||
TDW(0, "tdw"),
|
||||
MYSQL(1, "mysql"),
|
||||
DORIS(2, "doris"),
|
||||
CLICKHOUSE(3, "clickhouse"),
|
||||
KAFKA(4, "kafka"),
|
||||
H2(5, "h2"),
|
||||
POSTGRESQL(6, "postgresql"),
|
||||
OTHER(7, "other"),
|
||||
DUCKDB(8, "duckdb"),
|
||||
HANADB(9, "hanadb");
|
||||
|
||||
private Integer code;
|
||||
|
||||
|
||||
@@ -1,5 +1,73 @@
|
||||
package com.tencent.supersonic.common.pojo.enums;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum TimeDimensionEnum {
|
||||
DAY, WEEK, MONTH;
|
||||
DAY("sys_imp_date", "数据日期"),
|
||||
|
||||
WEEK("sys_imp_week", "数据日期_周"),
|
||||
|
||||
MONTH("sys_imp_month", "数据日期_月");
|
||||
|
||||
private String name;
|
||||
|
||||
private String chName;
|
||||
|
||||
TimeDimensionEnum(String name, String chName) {
|
||||
this.name = name;
|
||||
this.chName = chName;
|
||||
}
|
||||
|
||||
public static boolean containsTimeDimension(String fieldName) {
|
||||
if (getNameList().contains(fieldName) || getChNameList().contains(fieldName)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<String> getNameList() {
|
||||
return Arrays.stream(TimeDimensionEnum.values()).map(TimeDimensionEnum::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<String> getChNameList() {
|
||||
return Arrays.stream(TimeDimensionEnum.values()).map(TimeDimensionEnum::getChName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Map<String, String> getChNameToNameMap() {
|
||||
return Arrays.stream(TimeDimensionEnum.values()).collect(Collectors
|
||||
.toMap(TimeDimensionEnum::getChName, TimeDimensionEnum::getName, (k1, k2) -> k1));
|
||||
}
|
||||
|
||||
public static Map<String, String> getNameToNameMap() {
|
||||
return Arrays.stream(TimeDimensionEnum.values()).collect(Collectors
|
||||
.toMap(TimeDimensionEnum::getName, TimeDimensionEnum::getName, (k1, k2) -> k1));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getChName() {
|
||||
return chName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a time dimension field is included in a Chinese/English text field
|
||||
*
|
||||
* @param fields field
|
||||
* @return true/false
|
||||
*/
|
||||
public static boolean containsZhTimeDimension(List<String> fields) {
|
||||
if (CollectionUtils.isEmpty(fields)) {
|
||||
return false;
|
||||
}
|
||||
return fields.stream().anyMatch(field -> containsTimeDimension(field));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.tencent.supersonic.common.pojo.Constants;
|
||||
import com.tencent.supersonic.common.pojo.DateConf;
|
||||
import com.tencent.supersonic.common.pojo.ItemDateResp;
|
||||
import com.tencent.supersonic.common.pojo.enums.DatePeriodEnum;
|
||||
import com.tencent.supersonic.common.pojo.enums.TimeDimensionEnum;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -20,14 +21,22 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.tencent.supersonic.common.pojo.Constants.*;
|
||||
import static com.tencent.supersonic.common.pojo.Constants.APOSTROPHE;
|
||||
import static com.tencent.supersonic.common.pojo.Constants.COMMA;
|
||||
import static com.tencent.supersonic.common.pojo.Constants.DAY_FORMAT;
|
||||
import static com.tencent.supersonic.common.pojo.Constants.MONTH_FORMAT;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@Data
|
||||
public class DateModeUtils {
|
||||
|
||||
private final String sysDateCol = TimeDimensionEnum.DAY.getName();
|
||||
private final String sysDateMonthCol = TimeDimensionEnum.MONTH.getName();
|
||||
private final String sysDateWeekCol = TimeDimensionEnum.WEEK.getName();
|
||||
|
||||
@Value("${s2.query.parameter.sys.zipper.begin:start_}")
|
||||
private String sysZipperDateColBegin;
|
||||
|
||||
@@ -51,8 +60,8 @@ public class DateModeUtils {
|
||||
public String hasDataModeStr(ItemDateResp dateDate, DateConf dateInfo) {
|
||||
if (Objects.isNull(dateDate) || StringUtils.isEmpty(dateDate.getStartDate())
|
||||
|| StringUtils.isEmpty(dateDate.getStartDate())) {
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(),
|
||||
dateInfo.getStartDate(), dateInfo.getDateField(), dateInfo.getEndDate());
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol, dateInfo.getStartDate(),
|
||||
sysDateCol, dateInfo.getEndDate());
|
||||
} else {
|
||||
log.info("dateDate:{}", dateDate);
|
||||
}
|
||||
@@ -70,28 +79,27 @@ public class DateModeUtils {
|
||||
dateFormatStr, ChronoUnit.DAYS);
|
||||
LocalDate dateMax = endData;
|
||||
LocalDate dateMin = dateMax.minusDays(unit - 1);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(),
|
||||
dateMin, dateInfo.getDateField(), dateMax);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol, dateMin, sysDateCol,
|
||||
dateMax);
|
||||
}
|
||||
|
||||
if (DatePeriodEnum.MONTH.equals(dateInfo.getPeriod())) {
|
||||
Long unit = getInterval(dateInfo.getStartDate(), dateInfo.getEndDate(),
|
||||
dateFormatStr, ChronoUnit.MONTHS);
|
||||
return generateMonthSql(endData, unit, dateFormatStr, dateInfo);
|
||||
return generateMonthSql(endData, unit, dateFormatStr);
|
||||
}
|
||||
}
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(),
|
||||
dateInfo.getStartDate(), dateInfo.getDateField(), dateInfo.getEndDate());
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol, dateInfo.getStartDate(),
|
||||
sysDateCol, dateInfo.getEndDate());
|
||||
}
|
||||
|
||||
public String generateMonthSql(LocalDate endData, Long unit, String dateFormatStr,
|
||||
DateConf dateConf) {
|
||||
public String generateMonthSql(LocalDate endData, Long unit, String dateFormatStr) {
|
||||
LocalDate dateMax = endData;
|
||||
List<String> months = generateMonthStr(dateMax, unit, dateFormatStr);
|
||||
if (!CollectionUtils.isEmpty(months)) {
|
||||
StringJoiner joiner = new StringJoiner(",");
|
||||
months.stream().forEach(month -> joiner.add("'" + month + "'"));
|
||||
return String.format("(%s in (%s))", dateConf.getDateField(), joiner.toString());
|
||||
return String.format("(%s in (%s))", sysDateCol, joiner.toString());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -108,8 +116,8 @@ public class DateModeUtils {
|
||||
|
||||
public String recentDayStr(ItemDateResp dateDate, DateConf dateInfo) {
|
||||
ImmutablePair<String, String> dayRange = recentDay(dateDate, dateInfo);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(), dayRange.left,
|
||||
dateInfo.getDateField(), dayRange.right);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol, dayRange.left, sysDateCol,
|
||||
dayRange.right);
|
||||
}
|
||||
|
||||
public ImmutablePair<String, String> recentDay(ItemDateResp dateDate, DateConf dateInfo) {
|
||||
@@ -126,25 +134,24 @@ public class DateModeUtils {
|
||||
return ImmutablePair.of(start, dateDate.getEndDate());
|
||||
}
|
||||
|
||||
public String recentMonthStr(LocalDate endData, Long unit, String dateFormatStr,
|
||||
DateConf dateInfo) {
|
||||
public String recentMonthStr(LocalDate endData, Long unit, String dateFormatStr) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormatStr);
|
||||
String endStr = endData.format(formatter);
|
||||
String start = endData.minusMonths(unit).format(formatter);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(), start,
|
||||
dateInfo.getDateField(), endStr);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateMonthCol, start, sysDateMonthCol,
|
||||
endStr);
|
||||
}
|
||||
|
||||
public String recentMonthStr(ItemDateResp dateDate, DateConf dateInfo) {
|
||||
List<ImmutablePair<String, String>> range = recentMonth(dateDate, dateInfo);
|
||||
if (range.size() == 1) {
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(),
|
||||
range.get(0).left, dateInfo.getDateField(), range.get(0).right);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateMonthCol, range.get(0).left,
|
||||
sysDateMonthCol, range.get(0).right);
|
||||
}
|
||||
if (range.size() > 0) {
|
||||
StringJoiner joiner = new StringJoiner(",");
|
||||
range.stream().forEach(month -> joiner.add("'" + month.left + "'"));
|
||||
return String.format("(%s in (%s))", dateInfo.getDateField(), joiner.toString());
|
||||
return String.format("(%s in (%s))", sysDateCol, joiner.toString());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -174,17 +181,17 @@ public class DateModeUtils {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String recentWeekStr(LocalDate endData, Long unit, DateConf dataInfo) {
|
||||
public String recentWeekStr(LocalDate endData, Long unit) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DAY_FORMAT);
|
||||
String start = endData.minusDays(unit * 7).format(formatter);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dataInfo.getDateField(), start,
|
||||
dataInfo.getDateField(), endData.format(formatter));
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateWeekCol, start, sysDateWeekCol,
|
||||
endData.format(formatter));
|
||||
}
|
||||
|
||||
public String recentWeekStr(ItemDateResp dateDate, DateConf dateInfo) {
|
||||
ImmutablePair<String, String> dayRange = recentWeek(dateDate, dateInfo);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(), dayRange.left,
|
||||
dateInfo.getDateField(), dayRange.right);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateWeekCol, dayRange.left,
|
||||
sysDateWeekCol, dayRange.right);
|
||||
}
|
||||
|
||||
public ImmutablePair<String, String> recentWeek(ItemDateResp dateDate, DateConf dateInfo) {
|
||||
@@ -235,27 +242,26 @@ public class DateModeUtils {
|
||||
* @return
|
||||
*/
|
||||
public String betweenDateStr(DateConf dateInfo) {
|
||||
String dateField = dateInfo.getDateField();
|
||||
if (DatePeriodEnum.MONTH.equals(dateInfo.getPeriod())) {
|
||||
// startDate YYYYMM
|
||||
if (!dateInfo.getStartDate().contains(Constants.MINUS)) {
|
||||
return String.format("%s >= '%s' and %s <= '%s'", dateField,
|
||||
dateInfo.getStartDate(), dateField, dateInfo.getEndDate());
|
||||
return String.format("%s >= '%s' and %s <= '%s'", sysDateMonthCol,
|
||||
dateInfo.getStartDate(), sysDateMonthCol, dateInfo.getEndDate());
|
||||
}
|
||||
LocalDate endData =
|
||||
LocalDate.parse(dateInfo.getEndDate(), DateTimeFormatter.ofPattern(DAY_FORMAT));
|
||||
LocalDate startData = LocalDate.parse(dateInfo.getStartDate(),
|
||||
DateTimeFormatter.ofPattern(DAY_FORMAT));
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(MONTH_FORMAT);
|
||||
return String.format("%s >= '%s' and %s <= '%s'", dateField,
|
||||
startData.format(formatter), dateField, endData.format(formatter));
|
||||
return String.format("%s >= '%s' and %s <= '%s'", sysDateMonthCol,
|
||||
startData.format(formatter), sysDateMonthCol, endData.format(formatter));
|
||||
}
|
||||
if (DatePeriodEnum.WEEK.equals(dateInfo.getPeriod())) {
|
||||
return String.format("%s >= '%s' and %s <= '%s'", dateField, dateInfo.getStartDate(),
|
||||
dateField, dateInfo.getEndDate());
|
||||
return String.format("%s >= '%s' and %s <= '%s'", sysDateWeekCol,
|
||||
dateInfo.getStartDate(), sysDateWeekCol, dateInfo.getEndDate());
|
||||
}
|
||||
return String.format("%s >= '%s' and %s <= '%s'", dateField, dateInfo.getStartDate(),
|
||||
dateField, dateInfo.getEndDate());
|
||||
return String.format("%s >= '%s' and %s <= '%s'", sysDateCol, dateInfo.getStartDate(),
|
||||
sysDateCol, dateInfo.getEndDate());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,12 +273,12 @@ public class DateModeUtils {
|
||||
public String listDateStr(DateConf dateInfo) {
|
||||
StringJoiner joiner = new StringJoiner(COMMA);
|
||||
dateInfo.getDateList().stream().forEach(date -> joiner.add(APOSTROPHE + date + APOSTROPHE));
|
||||
String dateCol = dateInfo.getDateField();
|
||||
String dateCol = sysDateCol;
|
||||
if (DatePeriodEnum.MONTH.equals(dateInfo.getPeriod())) {
|
||||
dateCol = dateInfo.getDateField();
|
||||
dateCol = sysDateMonthCol;
|
||||
}
|
||||
if (DatePeriodEnum.WEEK.equals(dateInfo.getPeriod())) {
|
||||
dateCol = dateInfo.getDateField();
|
||||
dateCol = sysDateWeekCol;
|
||||
}
|
||||
return String.format("(%s in (%s))", dateCol, joiner.toString());
|
||||
}
|
||||
@@ -293,26 +299,25 @@ public class DateModeUtils {
|
||||
if (DatePeriodEnum.DAY.equals(dateInfo.getPeriod())) {
|
||||
LocalDate dateMax = LocalDate.now().minusDays(1);
|
||||
LocalDate dateMin = dateMax.minusDays(unit - 1);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(), dateMin,
|
||||
dateInfo.getDateField(), dateMax);
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol, dateMin, sysDateCol,
|
||||
dateMax);
|
||||
}
|
||||
|
||||
if (DatePeriodEnum.WEEK.equals(dateInfo.getPeriod())) {
|
||||
LocalDate dateMax = LocalDate.now().minusDays(1);
|
||||
return recentWeekStr(dateMax, unit.longValue(), dateInfo);
|
||||
return recentWeekStr(dateMax, unit.longValue());
|
||||
}
|
||||
if (DatePeriodEnum.MONTH.equals(dateInfo.getPeriod())) {
|
||||
LocalDate dateMax = LocalDate.now().minusDays(1);
|
||||
return recentMonthStr(dateMax, unit.longValue(), MONTH_FORMAT, dateInfo);
|
||||
return recentMonthStr(dateMax, unit.longValue(), MONTH_FORMAT);
|
||||
}
|
||||
if (DatePeriodEnum.YEAR.equals(dateInfo.getPeriod())) {
|
||||
LocalDate dateMax = LocalDate.now().minusDays(1);
|
||||
return recentMonthStr(dateMax, unit.longValue() * 12, MONTH_FORMAT, dateInfo);
|
||||
return recentMonthStr(dateMax, unit.longValue() * 12, MONTH_FORMAT);
|
||||
}
|
||||
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", dateInfo.getDateField(),
|
||||
LocalDate.now().minusDays(2), dateInfo.getDateField(),
|
||||
LocalDate.now().minusDays(1));
|
||||
return String.format("(%s >= '%s' and %s <= '%s')", sysDateCol,
|
||||
LocalDate.now().minusDays(2), sysDateCol, LocalDate.now().minusDays(1));
|
||||
}
|
||||
|
||||
public String getDateWhereStr(DateConf dateInfo) {
|
||||
@@ -344,7 +349,32 @@ public class DateModeUtils {
|
||||
}
|
||||
|
||||
public String getSysDateCol(DateConf dateInfo) {
|
||||
return dateInfo.getDateField();
|
||||
if (DatePeriodEnum.DAY.equals(dateInfo.getPeriod())) {
|
||||
return sysDateCol;
|
||||
}
|
||||
if (DatePeriodEnum.WEEK.equals(dateInfo.getPeriod())) {
|
||||
return sysDateWeekCol;
|
||||
}
|
||||
if (DatePeriodEnum.MONTH.equals(dateInfo.getPeriod())) {
|
||||
return sysDateMonthCol;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isDateStr(String date) {
|
||||
return Pattern.matches("[\\d\\s-:]+", date);
|
||||
}
|
||||
|
||||
public DatePeriodEnum getPeriodByCol(String col) {
|
||||
if (sysDateCol.equalsIgnoreCase(col)) {
|
||||
return DatePeriodEnum.DAY;
|
||||
}
|
||||
if (sysDateWeekCol.equalsIgnoreCase(col)) {
|
||||
return DatePeriodEnum.WEEK;
|
||||
}
|
||||
if (sysDateMonthCol.equalsIgnoreCase(col)) {
|
||||
return DatePeriodEnum.MONTH;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.tencent.supersonic.common.util;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
|
||||
public class S2ThreadContext {
|
||||
|
||||
private static final TransmittableThreadLocal<ThreadContext> context =
|
||||
new TransmittableThreadLocal<>();
|
||||
|
||||
public ThreadContext get() {
|
||||
return context.get();
|
||||
}
|
||||
|
||||
public void set(ThreadContext value) {
|
||||
context.set(value);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
context.remove();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.tencent.supersonic.common.util;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.User;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
@@ -14,7 +13,7 @@ public class ThreadContext {
|
||||
|
||||
private String traceId;
|
||||
|
||||
private User user;
|
||||
private String userName;
|
||||
|
||||
private String token;
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ public class OpenAiChatModel implements ChatLanguageModel, TokenCountEstimator {
|
||||
private final OpenAiClient client;
|
||||
private final String baseUrl;
|
||||
private final String modelName;
|
||||
private final String apiVersion;
|
||||
private final Double temperature;
|
||||
private final Double topP;
|
||||
private final List<String> stop;
|
||||
@@ -90,13 +89,12 @@ public class OpenAiChatModel implements ChatLanguageModel, TokenCountEstimator {
|
||||
|
||||
@Builder
|
||||
public OpenAiChatModel(String baseUrl, String apiKey, String organizationId, String modelName,
|
||||
String apiVersion, Double temperature, Double topP, List<String> stop,
|
||||
Integer maxTokens, Double presencePenalty, Double frequencyPenalty,
|
||||
Map<String, Integer> logitBias, String responseFormat, Boolean strictJsonSchema,
|
||||
Integer seed, String user, Boolean strictTools, Boolean parallelToolCalls,
|
||||
Duration timeout, Integer maxRetries, Proxy proxy, Boolean logRequests,
|
||||
Boolean logResponses, Tokenizer tokenizer, Map<String, String> customHeaders,
|
||||
List<ChatModelListener> listeners) {
|
||||
Double temperature, Double topP, List<String> stop, Integer maxTokens,
|
||||
Double presencePenalty, Double frequencyPenalty, Map<String, Integer> logitBias,
|
||||
String responseFormat, Boolean strictJsonSchema, Integer seed, String user,
|
||||
Boolean strictTools, Boolean parallelToolCalls, Duration timeout, Integer maxRetries,
|
||||
Proxy proxy, Boolean logRequests, Boolean logResponses, Tokenizer tokenizer,
|
||||
Map<String, String> customHeaders, List<ChatModelListener> listeners) {
|
||||
|
||||
baseUrl = getOrDefault(baseUrl, OPENAI_URL);
|
||||
if (OPENAI_DEMO_API_KEY.equals(apiKey)) {
|
||||
@@ -107,12 +105,11 @@ public class OpenAiChatModel implements ChatLanguageModel, TokenCountEstimator {
|
||||
timeout = getOrDefault(timeout, ofSeconds(60));
|
||||
|
||||
this.client = OpenAiClient.builder().openAiApiKey(apiKey).baseUrl(baseUrl)
|
||||
.apiVersion(apiVersion).organizationId(organizationId).callTimeout(timeout)
|
||||
.connectTimeout(timeout).readTimeout(timeout).writeTimeout(timeout).proxy(proxy)
|
||||
.logRequests(logRequests).logResponses(logResponses).userAgent(DEFAULT_USER_AGENT)
|
||||
.organizationId(organizationId).callTimeout(timeout).connectTimeout(timeout)
|
||||
.readTimeout(timeout).writeTimeout(timeout).proxy(proxy).logRequests(logRequests)
|
||||
.logResponses(logResponses).userAgent(DEFAULT_USER_AGENT)
|
||||
.customHeaders(customHeaders).build();
|
||||
this.modelName = getOrDefault(modelName, GPT_3_5_TURBO);
|
||||
this.apiVersion = apiVersion;
|
||||
this.temperature = getOrDefault(temperature, 0.7);
|
||||
this.topP = topP;
|
||||
this.stop = stop;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package dev.langchain4j.opensearch.spring;
|
||||
|
||||
import io.milvus.common.clientenum.ConsistencyLevelEnum;
|
||||
import io.milvus.param.IndexType;
|
||||
import io.milvus.param.MetricType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
class EmbeddingStoreProperties {
|
||||
|
||||
private String uri;
|
||||
private String host;
|
||||
private Integer port;
|
||||
private String serviceName;
|
||||
private String region;
|
||||
private String collectionName;
|
||||
private Integer dimension;
|
||||
private IndexType indexType;
|
||||
private MetricType metricType;
|
||||
private String token;
|
||||
private String user;
|
||||
private String password;
|
||||
private ConsistencyLevelEnum consistencyLevel;
|
||||
private Boolean retrieveEmbeddingsOnSearch;
|
||||
private String databaseName;
|
||||
private Boolean autoFlushOnInsert;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package dev.langchain4j.opensearch.spring;
|
||||
|
||||
import dev.langchain4j.store.embedding.EmbeddingStoreFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static dev.langchain4j.opensearch.spring.Properties.PREFIX;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(dev.langchain4j.opensearch.spring.Properties.class)
|
||||
public class OpenSearchAutoConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(PREFIX + ".embedding-store.uri")
|
||||
EmbeddingStoreFactory milvusChatModel(Properties properties) {
|
||||
return new OpenSearchEmbeddingStoreFactory(properties.getEmbeddingStore());
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package dev.langchain4j.opensearch.spring;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.EmbeddingStoreConfig;
|
||||
import dev.langchain4j.data.segment.TextSegment;
|
||||
import dev.langchain4j.store.embedding.BaseEmbeddingStoreFactory;
|
||||
import dev.langchain4j.store.embedding.EmbeddingStore;
|
||||
import dev.langchain4j.store.embedding.opensearch.OpenSearchEmbeddingStore;
|
||||
import org.apache.hc.client5.http.auth.AuthScope;
|
||||
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.opensearch.client.transport.aws.AwsSdk2TransportOptions;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
||||
|
||||
/**
|
||||
* @author zyc
|
||||
*/
|
||||
public class OpenSearchEmbeddingStoreFactory extends BaseEmbeddingStoreFactory {
|
||||
private final EmbeddingStoreProperties storeProperties;
|
||||
|
||||
public OpenSearchEmbeddingStoreFactory(EmbeddingStoreConfig storeConfig) {
|
||||
this(createPropertiesFromConfig(storeConfig));
|
||||
}
|
||||
|
||||
public OpenSearchEmbeddingStoreFactory(EmbeddingStoreProperties storeProperties) {
|
||||
this.storeProperties = storeProperties;
|
||||
}
|
||||
|
||||
private static EmbeddingStoreProperties createPropertiesFromConfig(
|
||||
EmbeddingStoreConfig storeConfig) {
|
||||
EmbeddingStoreProperties embeddingStore = new EmbeddingStoreProperties();
|
||||
BeanUtils.copyProperties(storeConfig, embeddingStore);
|
||||
embeddingStore.setUri(storeConfig.getBaseUrl());
|
||||
embeddingStore.setToken(storeConfig.getApiKey());
|
||||
embeddingStore.setDatabaseName(storeConfig.getDatabaseName());
|
||||
return embeddingStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddingStore<TextSegment> createEmbeddingStore(String collectionName) {
|
||||
final AwsSdk2TransportOptions options =
|
||||
AwsSdk2TransportOptions.builder()
|
||||
.setCredentials(StaticCredentialsProvider.create(AwsBasicCredentials
|
||||
.create(storeProperties.getUser(), storeProperties.getPassword())))
|
||||
.build();
|
||||
final String indexName = storeProperties.getDatabaseName() + "_" + collectionName;
|
||||
return OpenSearchEmbeddingStore.builder().serviceName(storeProperties.getServiceName())
|
||||
.serverUrl(storeProperties.getUri()).region(storeProperties.getRegion())
|
||||
.indexName(indexName).userName(storeProperties.getUser())
|
||||
.password(storeProperties.getPassword()).apiKey(storeProperties.getToken())
|
||||
.options(options).build();
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package dev.langchain4j.opensearch.spring;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = Properties.PREFIX)
|
||||
public class Properties {
|
||||
|
||||
static final String PREFIX = "langchain4j.opensearch";
|
||||
|
||||
@NestedConfigurationProperty
|
||||
dev.langchain4j.opensearch.spring.EmbeddingStoreProperties embeddingStore;
|
||||
}
|
||||
@@ -18,14 +18,13 @@ public class OpenAiModelFactory implements ModelFactory, InitializingBean {
|
||||
public static final String DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
||||
public static final String DEFAULT_MODEL_NAME = "gpt-4o-mini";
|
||||
public static final String DEFAULT_EMBEDDING_MODEL_NAME = "text-embedding-ada-002";
|
||||
public static final String DEFAULT_API_VERSION = "2024-02-01";
|
||||
|
||||
@Override
|
||||
public ChatLanguageModel createChatModel(ChatModelConfig modelConfig) {
|
||||
return OpenAiChatModel.builder().baseUrl(modelConfig.getBaseUrl())
|
||||
.modelName(modelConfig.getModelName()).apiKey(modelConfig.keyDecrypt())
|
||||
.apiVersion(modelConfig.getApiVersion()).temperature(modelConfig.getTemperature())
|
||||
.topP(modelConfig.getTopP()).maxRetries(modelConfig.getMaxRetries())
|
||||
.temperature(modelConfig.getTemperature()).topP(modelConfig.getTopP())
|
||||
.maxRetries(modelConfig.getMaxRetries())
|
||||
.timeout(Duration.ofSeconds(modelConfig.getTimeOut()))
|
||||
.logRequests(modelConfig.getLogRequests())
|
||||
.logResponses(modelConfig.getLogResponses()).build();
|
||||
|
||||
@@ -10,8 +10,6 @@ import dev.langchain4j.model.zhipu.ZhipuAiEmbeddingModel;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import static java.time.Duration.ofSeconds;
|
||||
|
||||
@Service
|
||||
public class ZhipuModelFactory implements ModelFactory, InitializingBean {
|
||||
public static final String PROVIDER = "ZHIPU";
|
||||
@@ -32,9 +30,8 @@ public class ZhipuModelFactory implements ModelFactory, InitializingBean {
|
||||
public EmbeddingModel createEmbeddingModel(EmbeddingModelConfig embeddingModelConfig) {
|
||||
return ZhipuAiEmbeddingModel.builder().baseUrl(embeddingModelConfig.getBaseUrl())
|
||||
.apiKey(embeddingModelConfig.getApiKey()).model(embeddingModelConfig.getModelName())
|
||||
.maxRetries(embeddingModelConfig.getMaxRetries()).callTimeout(ofSeconds(60))
|
||||
.connectTimeout(ofSeconds(60)).writeTimeout(ofSeconds(60))
|
||||
.readTimeout(ofSeconds(60)).logRequests(embeddingModelConfig.getLogRequests())
|
||||
.maxRetries(embeddingModelConfig.getMaxRetries())
|
||||
.logRequests(embeddingModelConfig.getLogRequests())
|
||||
.logResponses(embeddingModelConfig.getLogResponses()).build();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import dev.langchain4j.chroma.spring.ChromaEmbeddingStoreFactory;
|
||||
import dev.langchain4j.inmemory.spring.InMemoryEmbeddingStoreFactory;
|
||||
import dev.langchain4j.milvus.spring.MilvusEmbeddingStoreFactory;
|
||||
import dev.langchain4j.opensearch.spring.OpenSearchEmbeddingStoreFactory;
|
||||
import dev.langchain4j.pgvector.spring.PgvectorEmbeddingStoreFactory;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -46,11 +45,6 @@ public class EmbeddingStoreFactoryProvider {
|
||||
return factoryMap.computeIfAbsent(embeddingStoreConfig,
|
||||
storeConfig -> new InMemoryEmbeddingStoreFactory(storeConfig));
|
||||
}
|
||||
if (EmbeddingStoreType.OPENSEARCH.name()
|
||||
.equalsIgnoreCase(embeddingStoreConfig.getProvider())) {
|
||||
return factoryMap.computeIfAbsent(embeddingStoreConfig,
|
||||
storeConfig -> new OpenSearchEmbeddingStoreFactory(storeConfig));
|
||||
}
|
||||
throw new RuntimeException("Unsupported EmbeddingStoreFactory provider: "
|
||||
+ embeddingStoreConfig.getProvider());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package dev.langchain4j.store.embedding;
|
||||
|
||||
public enum EmbeddingStoreType {
|
||||
IN_MEMORY, MILVUS, CHROMA, PGVECTOR, OPENSEARCH
|
||||
IN_MEMORY, MILVUS, CHROMA, PGVECTOR
|
||||
}
|
||||
|
||||
@@ -2,10 +2,8 @@ package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.jsqlparser.DateVisitor.DateBoundInfo;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Disabled
|
||||
class SqlDateSelectHelperTest {
|
||||
|
||||
@Test
|
||||
@@ -13,31 +11,31 @@ class SqlDateSelectHelperTest {
|
||||
|
||||
String sql = "SELECT 维度1,sum(播放量) FROM 数据库 "
|
||||
+ "WHERE (歌手名 = '张三') AND 数据日期 >= '2023-11-17' GROUP BY 维度1";
|
||||
DateBoundInfo dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql, "数据日期");
|
||||
DateBoundInfo dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql);
|
||||
Assert.assertEquals(dateBoundInfo.getLowerBound(), ">=");
|
||||
Assert.assertEquals(dateBoundInfo.getLowerDate(), "2023-11-17");
|
||||
|
||||
sql = "SELECT 维度1,sum(播放量) FROM 数据库 "
|
||||
+ "WHERE (歌手名 = '张三') AND 数据日期 > '2023-11-17' GROUP BY 维度1";
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql, "数据日期");
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql);
|
||||
Assert.assertEquals(dateBoundInfo.getLowerBound(), ">");
|
||||
Assert.assertEquals(dateBoundInfo.getLowerDate(), "2023-11-17");
|
||||
|
||||
sql = "SELECT 维度1,sum(播放量) FROM 数据库 "
|
||||
+ "WHERE (歌手名 = '张三') AND 数据日期 <= '2023-11-17' GROUP BY 维度1";
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql, "数据日期");
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql);
|
||||
Assert.assertEquals(dateBoundInfo.getUpperBound(), "<=");
|
||||
Assert.assertEquals(dateBoundInfo.getUpperDate(), "2023-11-17");
|
||||
|
||||
sql = "SELECT 维度1,sum(播放量) FROM 数据库 "
|
||||
+ "WHERE (歌手名 = '张三') AND 数据日期 < '2023-11-17' GROUP BY 维度1";
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql, "数据日期");
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql);
|
||||
Assert.assertEquals(dateBoundInfo.getUpperBound(), "<");
|
||||
Assert.assertEquals(dateBoundInfo.getUpperDate(), "2023-11-17");
|
||||
|
||||
sql = "SELECT 维度1,sum(播放量) FROM 数据库 " + "WHERE (歌手名 = '张三') AND 数据日期 >= '2023-10-17' "
|
||||
+ "AND 数据日期 <= '2023-11-17' GROUP BY 维度1";
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql, "数据日期");
|
||||
dateBoundInfo = SqlDateSelectHelper.getDateBoundInfo(sql);
|
||||
Assert.assertEquals(dateBoundInfo.getUpperBound(), "<=");
|
||||
Assert.assertEquals(dateBoundInfo.getUpperDate(), "2023-11-17");
|
||||
Assert.assertEquals(dateBoundInfo.getLowerBound(), ">=");
|
||||
|
||||
@@ -157,14 +157,6 @@ class SqlRemoveHelperTest {
|
||||
replaceSql = SqlRemoveHelper.removeWhereCondition(sql, removeFieldNames);
|
||||
Assert.assertEquals("SELECT 歌曲名 FROM 歌曲库 WHERE (datediff('day', 发布日期, '2023-08-09') <= 1) "
|
||||
+ "AND 数据日期 = '2023-08-09' ORDER BY 播放量 DESC LIMIT 11", replaceSql);
|
||||
|
||||
sql = "select 歌曲名 from 歌曲库 where datediff('day', 发布日期, '2023-08-09') <= 1 "
|
||||
+ "and 歌曲名 between '2023-08-09' and '2024-08-09' and 数据日期 = '2023-08-09' and 歌曲发布时 = '2023-08-01'"
|
||||
+ " order by 播放量 desc limit 11";
|
||||
replaceSql = SqlRemoveHelper.removeWhereCondition(sql, removeFieldNames);
|
||||
Assert.assertEquals("SELECT 歌曲名 FROM 歌曲库 WHERE datediff('day', 发布日期, '2023-08-09') <= 1 "
|
||||
+ "AND 数据日期 = '2023-08-09' AND 歌曲发布时 = '2023-08-01' "
|
||||
+ "ORDER BY 播放量 DESC LIMIT 11", replaceSql);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,16 +1,38 @@
|
||||
package com.tencent.supersonic.common.jsqlparser;
|
||||
|
||||
import com.tencent.supersonic.common.pojo.enums.AggOperatorEnum;
|
||||
import com.tencent.supersonic.common.util.ContextUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
|
||||
/**
|
||||
* SqlParserReplaceHelperTest
|
||||
*/
|
||||
class SqlReplaceHelperTest {
|
||||
private MockedStatic<ContextUtils> mockedContextUtils;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
ReplaceService replaceService = new ReplaceService();
|
||||
replaceService.setReplaceColumnThreshold(0.4);
|
||||
|
||||
// Mock the static method ContextUtils.getBean
|
||||
mockedContextUtils = mockStatic(ContextUtils.class);
|
||||
mockedContextUtils.when(() -> ContextUtils.getBean(ReplaceService.class))
|
||||
.thenReturn(replaceService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReplaceAggField() {
|
||||
@@ -302,70 +324,6 @@ class SqlReplaceHelperTest {
|
||||
replaceSql);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReplaceAliasWithBackticks() {
|
||||
String sql = "SELECT 部门, SUM(访问次数) AS 总访问次数 FROM 超音数 WHERE "
|
||||
+ "datediff('day', 数据日期, '2023-09-05') <= 3 GROUP BY 部门 ORDER BY 总访问次数 DESC LIMIT 10";
|
||||
String replaceSql = SqlReplaceHelper.replaceAliasWithBackticks(sql);
|
||||
System.out.println(replaceSql);
|
||||
Assert.assertEquals("SELECT 部门, SUM(访问次数) AS `总访问次数` FROM 超音数 WHERE "
|
||||
+ "datediff('day', 数据日期, '2023-09-05') <= 3 GROUP BY 部门 ORDER BY `总访问次数` DESC LIMIT 10",
|
||||
replaceSql);
|
||||
|
||||
sql = "select 部门, sum(访问次数) as 访问次数 from 超音数 where "
|
||||
+ "(datediff('day', 数据日期, '2023-09-05') <= 3) and 数据日期 = '2023-10-10' "
|
||||
+ "group by 部门 order by 访问次数 desc limit 10";
|
||||
replaceSql = SqlReplaceHelper.replaceAliasWithBackticks(sql);
|
||||
System.out.println(replaceSql);
|
||||
Assert.assertEquals("SELECT 部门, sum(访问次数) AS `访问次数` FROM 超音数 WHERE (datediff('day', 数据日期, "
|
||||
+ "'2023-09-05') <= 3) AND 数据日期 = '2023-10-10' GROUP BY 部门 ORDER BY `访问次数` DESC LIMIT 10",
|
||||
replaceSql);
|
||||
|
||||
sql = "select 部门, sum(访问次数) as 访问次数, count(部门) as 部门数, count(部门) as 部门数2, 访问次数 from 超音数 where "
|
||||
+ "(datediff('day', 数据日期, '2023-09-05') <= 3) and 数据日期 = '2023-10-10' "
|
||||
+ "group by 部门, 部门数, 部门数2 having 访问次数 > 1 AND 部门数2 > 2 AND 部门数 > 1 AND 访问次数 > 1 order by 访问次数 desc limit 10";
|
||||
replaceSql = SqlReplaceHelper.replaceAliasWithBackticks(sql);
|
||||
System.out.println(replaceSql);
|
||||
Assert.assertEquals(
|
||||
"SELECT 部门, sum(访问次数) AS `访问次数`, count(部门) AS `部门数`, count(部门) AS `部门数2`, `访问次数` FROM 超音数 WHERE (datediff('day', 数据日期, "
|
||||
+ "'2023-09-05') <= 3) AND 数据日期 = '2023-10-10' GROUP BY 部门, `部门数`, `部门数2` HAVING `访问次数` > 1 AND `部门数2` > 2 AND `部门数` > 1 AND `访问次数` > 1 ORDER BY `访问次数` DESC LIMIT 10",
|
||||
replaceSql);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReplaceAliasFieldName() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("总访问次数", "\"总访问次数\"");
|
||||
map.put("访问次数", "\"访问次数\"");
|
||||
String sql = "select 部门, sum(访问次数) as 总访问次数 from 超音数 where "
|
||||
+ "datediff('day', 数据日期, '2023-09-05') <= 3 group by 部门 order by 总访问次数 desc limit 10";
|
||||
String replaceSql = SqlReplaceHelper.replaceAliasFieldName(sql, map);
|
||||
System.out.println(replaceSql);
|
||||
Assert.assertEquals("SELECT 部门, sum(访问次数) AS \"总访问次数\" FROM 超音数 WHERE "
|
||||
+ "datediff('day', 数据日期, '2023-09-05') <= 3 GROUP BY 部门 ORDER BY \"总访问次数\" DESC LIMIT 10",
|
||||
replaceSql);
|
||||
|
||||
sql = "select 部门, sum(访问次数) as 总访问次数 from 超音数 where "
|
||||
+ "(datediff('day', 数据日期, '2023-09-05') <= 3) and 数据日期 = '2023-10-10' "
|
||||
+ "group by 部门 order by 总访问次数 desc limit 10";
|
||||
replaceSql = SqlReplaceHelper.replaceAliasFieldName(sql, map);
|
||||
System.out.println(replaceSql);
|
||||
Assert.assertEquals("SELECT 部门, sum(访问次数) AS \"总访问次数\" FROM 超音数 WHERE "
|
||||
+ "(datediff('day', 数据日期, '2023-09-05') <= 3) AND 数据日期 = '2023-10-10' "
|
||||
+ "GROUP BY 部门 ORDER BY \"总访问次数\" DESC LIMIT 10", replaceSql);
|
||||
|
||||
sql = "select 部门, sum(访问次数) as 访问次数 from 超音数 where "
|
||||
+ "(datediff('day', 数据日期, '2023-09-05') <= 3) and 数据日期 = '2023-10-10' "
|
||||
+ "group by 部门 order by 访问次数 desc limit 10";
|
||||
replaceSql = SqlReplaceHelper.replaceAliasFieldName(sql, map);
|
||||
System.out.println(replaceSql);
|
||||
Assert.assertEquals(
|
||||
"SELECT 部门, sum(\"访问次数\") AS \"访问次数\" FROM 超音数 WHERE (datediff('day', 数据日期, "
|
||||
+ "'2023-09-05') <= 3) AND 数据日期 = '2023-10-10' GROUP BY 部门 ORDER BY \"访问次数\" DESC LIMIT 10",
|
||||
replaceSql);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReplaceAggAliasOrderbyField() {
|
||||
String sql = "SELECT SUM(访问次数) AS top10总播放量 FROM (SELECT 部门, SUM(访问次数) AS 访问次数 FROM 超音数 "
|
||||
@@ -394,4 +352,11 @@ class SqlReplaceHelperTest {
|
||||
return fieldToBizName;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
// Close the mocked static context
|
||||
if (mockedContextUtils != null) {
|
||||
mockedContextUtils.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
FROM supersonicbi/supersonic:0.9.10-SNAPSHOT
|
||||
# Use an official OpenJDK runtime as a parent image
|
||||
FROM openjdk:8-jdk
|
||||
|
||||
# Set the working directory in the container
|
||||
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
|
||||
ARG SUPERSONIC_VERSION
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
# Install necessary packages, including Postgres client
|
||||
RUN apt-get update && apt-get install -y postgresql-client
|
||||
|
||||
# Install the vim editor.
|
||||
RUN apt-get update && apt-get install -y vim && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Update the package list and install iputils-ping.
|
||||
RUN apt-get update && apt-get install -y iputils-ping
|
||||
|
||||
# 更新包列表并安装 dnsutils 包
|
||||
RUN apt-get update && apt-get install -y dnsutils
|
||||
|
||||
# Copy the supersonic standalone zip file into the container
|
||||
COPY assembly/build/supersonic-standalone-${SUPERSONIC_VERSION}.zip .
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Function to execute the build script
|
||||
execute_build_script() {
|
||||
echo "Executing build script: assembly/bin/supersonic-build.sh"
|
||||
assembly/bin/supersonic-build.sh
|
||||
}
|
||||
|
||||
# Function to build the Docker image
|
||||
build_docker_image() {
|
||||
local version=$1
|
||||
echo "Building Docker image: supersonic:$version"
|
||||
docker buildx build --no-cache --platform linux/amd64,linux/arm64 \
|
||||
--build-arg SUPERSONIC_VERSION=$version \
|
||||
-t supersonicbi/supersonic:$version \
|
||||
-t supersonicbi/supersonic:latest \
|
||||
-f docker/Dockerfile \
|
||||
--push .
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Docker build failed. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
echo "Docker image supersonic:$version built successfully."
|
||||
}
|
||||
|
||||
# Main script execution
|
||||
VERSION=$1
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Usage: $0 <version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
execute_build_script
|
||||
build_docker_image $VERSION
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SUPERSONIC_VERSION=latest docker-compose -f docker-compose.yml -p supersonic up
|
||||
SUPERSONIC_VERSION=0.9.10-SNAPSHOT docker-compose -f docker-compose.yml -p supersonic up
|
||||
@@ -1,5 +1,5 @@
|
||||
services:
|
||||
supersonic_postgres:
|
||||
postgres:
|
||||
image: pgvector/pgvector:pg17
|
||||
privileged: true
|
||||
container_name: supersonic_postgres
|
||||
@@ -11,8 +11,8 @@ services:
|
||||
POSTGRES_PASSWORD: supersonic_password
|
||||
ports:
|
||||
- "15432:5432"
|
||||
# volumes:
|
||||
# - postgres_data:/var/lib/postgresql
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql
|
||||
networks:
|
||||
- supersonic_network
|
||||
dns:
|
||||
@@ -21,10 +21,35 @@ services:
|
||||
- 8.8.4.4
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "sh -c 'pg_isready -U supersonic_user -d postgres'"]
|
||||
interval: 10s
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
|
||||
db_init:
|
||||
image: supersonicbi/supersonic:${SUPERSONIC_VERSION:-latest}
|
||||
privileged: true
|
||||
container_name: supersonic_db_init
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- supersonic_network
|
||||
command: >
|
||||
sh -c "
|
||||
if ! PGPASSWORD=supersonic_password psql -h supersonic_postgres -U supersonic_user -d postgres -c 'select * from s2_database limit 1' > /dev/null;
|
||||
then
|
||||
PGPASSWORD=supersonic_password psql -hsupersonic_postgres -U supersonic_user -d postgres < /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}/conf/db/schema-postgres.sql
|
||||
PGPASSWORD=supersonic_password psql -hsupersonic_postgres -U supersonic_user -d postgres < /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}/conf/db/schema-postgres-demo.sql
|
||||
PGPASSWORD=supersonic_password psql -hsupersonic_postgres -U supersonic_user -d postgres < /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}/conf/db/data-postgres.sql
|
||||
PGPASSWORD=supersonic_password psql -hsupersonic_postgres -U supersonic_user -d postgres < /usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}/conf/db/data-postgres-demo.sql
|
||||
else
|
||||
echo 'Database already initialized.'
|
||||
fi"
|
||||
dns:
|
||||
- 114.114.114.114
|
||||
- 8.8.8.8
|
||||
- 8.8.4.4
|
||||
|
||||
supersonic_standalone:
|
||||
image: supersonicbi/supersonic:${SUPERSONIC_VERSION:-latest}
|
||||
privileged: true
|
||||
@@ -37,17 +62,19 @@ services:
|
||||
ports:
|
||||
- "9080:9080"
|
||||
depends_on:
|
||||
supersonic_postgres:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
db_init:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- supersonic_network
|
||||
dns:
|
||||
- 114.114.114.114
|
||||
- 8.8.8.8
|
||||
- 8.8.4.4
|
||||
#volumes:
|
||||
volumes:
|
||||
#1.Named Volumes are best for persistent data managed by Docker.
|
||||
#- supersonic_data:/usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}
|
||||
- supersonic_data:/usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}
|
||||
#2.Bind Mounts are suitable for frequent modifications and debugging.
|
||||
# - ./conf/application-prd.yaml:/usr/src/app/supersonic-standalone-${SUPERSONIC_VERSION:-latest}/conf/application-prd.yaml
|
||||
#3.Detailed Bind Mounts offer more control over the mount behavior.
|
||||
@@ -57,9 +84,9 @@ services:
|
||||
# bind:
|
||||
# propagation: rprivate
|
||||
# create_host_path: true
|
||||
#volumes:
|
||||
# postgres_data:
|
||||
# supersonic_data:
|
||||
volumes:
|
||||
postgres_data:
|
||||
supersonic_data:
|
||||
|
||||
networks:
|
||||
supersonic_network:
|
||||
24
docker/docker-publish.sh
Normal file
24
docker/docker-publish.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Exit immediately if a command exits with a non-zero status
|
||||
set -e
|
||||
VERSION=$1
|
||||
|
||||
# Image name
|
||||
IMAGE_NAME="supersonicbi/supersonic"
|
||||
|
||||
# Default tag is latest
|
||||
TAGS="latest"
|
||||
|
||||
# If VERSION is provided, add it to TAGS and tag the image as latest
|
||||
if [ -n "$VERSION" ]; then
|
||||
TAGS="$TAGS $VERSION"
|
||||
docker tag $IMAGE_NAME:$VERSION $IMAGE_NAME:latest
|
||||
fi
|
||||
|
||||
# Push Docker images
|
||||
for TAG in $TAGS; do
|
||||
echo "Pushing Docker image $IMAGE_NAME:$TAG"
|
||||
docker push $IMAGE_NAME:$TAG
|
||||
done
|
||||
|
||||
echo "Docker images pushed successfully."
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user