一、原始需求分析
DuckDB发布1.0版本后,貌似性能很强悍的样子,它是一个单机的嵌入式数据路,支持SQL语言操作数据,所以现在的需求是:基于DuckDB实现一个数据关联碰撞分析的功能。
1、定义一套标准的JSON格式规范,让使用方按规范传入JSON实体,方便后续提供API接口让前端页面调用;
2、根据JSON格式规范,采用JAVA语言开发解释代码,生成最终的SQL查询语句;
3、在DuckDB执行最终的SQL查询语句,返回结果;
根据需要内容,首先找一下有没现成的JSON转SQL的规范和开源框架,发现还没有符合要求的,所以需要定义JSON格式规范。
总体流程为:
二、JSON格式规范设计
以上,大模型已经按提示要求,完成了JSON格式规范的定义,其实它还把规范的必填、可选、描述、每个结构的示例都输出了,只是这里没有粘贴上来。结果如下:
JSON格式规范文档
1、顶层结构
2、示例JSON数据
{
"select": ["users.name", "users.email", {"function": "COUNT", "field": "*", "alias": "post_count"}],
"from": "users",
"joins": [
{
"type": "INNER JOIN",
"table": "posts",
"on": {
"conditions": [
{"left": "users.id", "operator": "=", "right": "posts.user_id"},
{"left": "users.status", "operator": "=", "right": "posts.status"}
],
"logic": "AND"
}
}
],
"where": {
"conditions": [
{
"logic": "AND",
"conditions": [
{"field": "users.age", "operator": ">", "value": 21},
{"field": "users.status", "operator": "=", "value": "active"}
]
},
{
"logic": "OR",
"conditions": [
{"field": "users.name", "operator": "=", "value": "Alice"},
{"field": "users.name", "operator": "=", "value": "Carol"}
]
}
],
"logic": "AND"
},
"group_by": ["users.name", "users.email"],
"having": {
"conditions": [
{"field": "post_count", "operator": ">", "value": 1}
], "logic": "AND" },
"order_by": [
{"field": "users.name", "direction": "ASC"}
],
"limit": 10,
"offset": 0
}
三、JAVA代码实现JSON转SQL
一开始大模型使用org.json库来解释JSON,它可以快速按我的指示,使用fastjson库来实现。
四、JAVA代码实现DuckDB读写
1、完整的Java代码
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JSONToSQL {
public static void main(String[] args) {
try {
// 示例JSON数据
String jsonString = "{\n" +
" \"select\": [\"users.name\", \"users.email\", {\"function\": \"COUNT\", \"field\": \"*\", \"alias\": \"post_count\"}],\n" +
" \"from\": \"users\",\n" +
" \"joins\": [\n" +
" {\n" +
" \"type\": \"INNER JOIN\",\n" +
" \"table\": \"posts\",\n" +
" \"on\": {\n" +
" \"conditions\": [\n" +
" {\"left\": \"users.id\", \"operator\": \"=\", \"right\": \"posts.user_id\"},\n" +
" {\"left\": \"users.status\", \"operator\": \"=\", \"right\": \"posts.status\"}\n" +
" ],\n" +
" \"logic\": \"AND\"\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"where\": {\n" +
" \"conditions\": [\n" +
" {\n" +
" \"logic\": \"AND\",\n" +
" \"conditions\": [\n" +
" {\"field\": \"users.age\", \"operator\": \">\", \"value\": 21},\n" +
" {\"field\": \"users.status\", \"operator\": \"=\", \"value\": \"active\"}\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"logic\": \"OR\",\n" +
" \"conditions\": [\n" +
" {\"field\": \"users.name\", \"operator\": \"=\", \"value\": \"Alice\"},\n" +
" {\"field\": \"users.name\", \"operator\": \"=\", \"value\": \"Carol\"}\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"logic\": \"AND\"\n" +
" },\n" +
" \"group_by\": [\"users.name\", \"users.email\"],\n" +
" \"having\": {\n" +
" \"conditions\": [\n" +
" {\"field\": \"post_count\", \"operator\": \">\", \"value\": 1}\n" +
" ],\n" +
" \"logic\": \"AND\"\n" +
" },\n" +
" \"order_by\": [\n" +
" {\"field\": \"users.name\", \"direction\": \"ASC\"}\n" +
" ],\n" +
" \"limit\": 10,\n" +
" \"offset\": 0\n" +
"}";
// 解析JSON并生成SQL查询
JSONObject json = JSONObject.parseObject(jsonString);
String sqlQuery = jsonToSQL(json);
System.out.println("Generated SQL Query: " + sqlQuery);
// 创建DuckDB连接
Connection conn = DriverManager.getConnection("jdbc:duckdb:");
Statement stmt = conn.createStatement();
// 创建示例数据表
stmt.execute("CREATE TABLE users (id INTEGER, name VARCHAR, email VARCHAR, age INTEGER, status VARCHAR);");
stmt.execute("CREATE TABLE posts (id INTEGER, user_id INTEGER, title VARCHAR, content VARCHAR, status VARCHAR);");
// 插入示例数据
stmt.execute("INSERT INTO users VALUES (1, 'Alice', 'alice@example.com', 25, 'active');");
stmt.execute("INSERT INTO users VALUES (2, 'Bob', 'bob@example.com', 30, 'inactive');");
stmt.execute("INSERT INTO users VALUES (3, 'Carol', 'carol@example.com', 22, 'active');");
stmt.execute("INSERT INTO posts VALUES (1, 1, 'Post 1', 'Content 1', 'active');");
stmt.execute("INSERT INTO posts VALUES (2, 1, 'Post 2', 'Content 2', 'active');");
stmt.execute("INSERT INTO posts VALUES (3, 2, 'Post 3', 'Content 3', 'inactive');");
stmt.execute("INSERT INTO posts VALUES (4, 3, 'Post 4', 'Content 4', 'active');");
stmt.execute("INSERT INTO posts VALUES (5, 3, 'Post 5', 'Content 5', 'active');");
// 执行生成的SQL查询
ResultSet rs = stmt.executeQuery(sqlQuery);
// 显示查询结果
while (rs.next()) {
System.out.println("Name: " + rs.getString("name"));
System.out.println("Email: " + rs.getString("email"));
System.out.println("Post Count: " + rs.getInt("post_count"));
System.out.println("----");
}
// 关闭连接
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static String jsonToSQL(JSONObject json) {
StringBuilder sql = new StringBuilder();
// SELECT clause
sql.append("SELECT ");
JSONArray selectArray = json.getJSONArray("select");
for (int i = 0; i < selectArray.size(); i++) {
Object item = selectArray.get(i);
if (item instanceof String) {
sql.append(item);
} else if (item instanceof JSONObject) {
JSONObject functionObj = (JSONObject) item;
sql.append(functionObj.getString("function"))
.append("(")
.append(functionObj.getString("field"))
.append(") AS ")
.append(functionObj.getString("alias"));
}
if (i < selectArray.size() - 1) {
sql.append(", ");
}
}
// FROM clause
sql.append(" FROM ").append(json.getString("from"));
// JOINS clause
if (json.containsKey("joins")) {
JSONArray joinsArray = json.getJSONArray("joins");
for (int i = 0; i < joinsArray.size(); i++) {
JSONObject joinObj = joinsArray.getJSONObject(i);
sql.append(" ").append(joinObj.getString("type"))
.append(" ").append(joinObj.getString("table"))
.append(" ON ");
JSONObject onObj = joinObj.getJSONObject("on");
JSONArray conditionsArray = onObj.getJSONArray("conditions");
String logic = onObj.getString("logic");
for (int j = 0; j < conditionsArray.size(); j++) {
JSONObject condition = conditionsArray.getJSONObject(j);
sql.append(condition.getString("left"))
.append(" ").append(condition.getString("operator"))
.append(" ").append(condition.getString("right"));
if (j < conditionsArray.size() - 1) {
sql.append(" ").append(logic).append(" ");
}
}
}
}
// WHERE clause
if (json.containsKey("where")) {
sql.append(" WHERE ");
appendConditions(sql, json.getJSONObject("where"));
}
// GROUP BY clause
if (json.containsKey("group_by")) {
sql.append(" GROUP BY ");
JSONArray groupByArray = json.getJSONArray("group_by");
for (int i = 0; i < groupByArray.size(); i++) {
sql.append(groupByArray.getString(i));
if (i < groupByArray.size() - 1) {
sql.append(", ");
}
}
}
// HAVING clause
if (json.containsKey("having")) {
sql.append(" HAVING ");
appendConditions(sql, json.getJSONObject("having"));
}
// ORDER BY clause
if (json.containsKey("order_by")) {
sql.append(" ORDER BY ");
JSONArray orderByArray = json.getJSONArray("order_by");
for (int i = 0; i < orderByArray.size(); i++) {
JSONObject orderBy = orderByArray.getJSONObject(i);
sql.append(orderBy.getString("field"))
.append(" ").append(orderBy.getString("direction"));
if (i < orderByArray.size() - 1) {
sql.append(", ");
}
}
}
// LIMIT clause
if (json.containsKey("limit")) {
sql.append(" LIMIT ").append(json.getIntValue("limit"));
}
// OFFSET clause
if (json.containsKey("offset")) {
sql.append(" OFFSET ").append(json.getIntValue("offset"));
}
sql.append(";");
return sql.toString();
}
private static void appendConditions(StringBuilder sql,
JSONObject conditionObj) { JSONArray conditionsArray = conditionObj.getJSONArray("conditions");
String logic = conditionObj.getString("logic");
for (int i = 0; i < conditionsArray.size(); i++) {
Object item = conditionsArray.get(i);
if (item instanceof JSONObject && ((JSONObject) item).containsKey("conditions")) {
sql.append("(");
appendConditions(sql, (JSONObject) item);
sql.append(")");
} else {
JSONObject condition = (JSONObject) item;
sql.append(condition.getString("field"))
.append(" ").append(condition.getString("operator"))
.append(" ");
Object value = condition.get("value");
if (value instanceof String) {
sql.append("'").append(value).append("'");
} else {
sql.append(value);
}
}
if (i < conditionsArray.size() - 1) {
sql.append(" ").append(logic).append(" ");
}
}
}
}
五、单元测试
1、单元测试代码
import com.alibaba.fastjson.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import static org.junit.Assert.*;
public class JSONToSQLTest {
private Connection conn;
private Statement stmt;
@Before
public void setUp() throws Exception {
// 创建DuckDB连接
conn = DriverManager.getConnection("jdbc:duckdb:");
stmt = conn.createStatement();
// 创建示例数据表
stmt.execute("CREATE TABLE users (id INTEGER, name VARCHAR, email VARCHAR, age INTEGER, status VARCHAR);");
stmt.execute("CREATE TABLE posts (id INTEGER, user_id INTEGER, title VARCHAR, content VARCHAR, status VARCHAR);");
// 插入示例数据
stmt.execute("INSERT INTO users VALUES (1, 'Alice', 'alice@example.com', 25, 'active');");
stmt.execute("INSERT INTO users VALUES (2, 'Bob', 'bob@example.com', 30, 'inactive');");
stmt.execute("INSERT INTO users VALUES (3, 'Carol', 'carol@example.com', 22, 'active');");
stmt.execute("INSERT INTO posts VALUES (1, 1, 'Post 1', 'Content 1', 'active');");
stmt.execute("INSERT INTO posts VALUES (2, 1, 'Post 2', 'Content 2', 'active');");
stmt.execute("INSERT INTO posts VALUES (3, 2, 'Post 3', 'Content 3', 'inactive');");
stmt.execute("INSERT INTO posts VALUES (4, 3, 'Post 4', 'Content 4', 'active');");
stmt.execute("INSERT INTO posts VALUES (5, 3, 'Post 5', 'Content 5', 'active');");
}
@After
public void tearDown() throws Exception {
stmt.execute("DROP TABLE users;");
stmt.execute("DROP TABLE posts;");
stmt.close();
conn.close();
}
@Test
public void testJsonToSQL() throws Exception {
// 示例JSON数据
String jsonString = "{\n" +
" \"select\": [\"users.name\", \"users.email\", {\"function\": \"COUNT\", \"field\": \"*\", \"alias\": \"post_count\"}],\n" +
" \"from\": \"users\",\n" +
" \"joins\": [\n" +
" {\n" +
" \"type\": \"INNER JOIN\",\n" +
" \"table\": \"posts\",\n" +
" \"on\": {\n" +
" \"conditions\": [\n" +
" {\"left\": \"users.id\", \"operator\": \"=\", \"right\": \"posts.user_id\"},\n" +
" {\"left\": \"users.status\", \"operator\": \"=\", \"right\": \"posts.status\"}\n" +
" ],\n" +
" \"logic\": \"AND\"\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"where\": {\n" +
" \"conditions\": [\n" +
" {\n" +
" \"logic\": \"AND\",\n" +
" \"conditions\": [\n" +
" {\"field\": \"users.age\", \"operator\": \">\", \"value\": 21},\n" +
" {\"field\": \"users.status\", \"operator\": \"=\", \"value\": \"active\"}\n" +
" ]\n" +
" },\n" +
" {\n" +
" \"logic\": \"OR\",\n" +
" \"conditions\": [\n" +
" {\"field\": \"users.name\", \"operator\": \"=\", \"value\": \"Alice\"},\n" +
" {\"field\": \"users.name\", \"operator\": \"=\", \"value\": \"Carol\"}\n" +
" ]\n" +
" }\n" +
" ],\n" +
" \"logic\": \"AND\"\n" +
" },\n" +
" \"group_by\": [\"users.name\", \"users.email\"],\n" +
" \"having\": {\n" +
" \"conditions\": [\n" +
" {\"field\": \"post_count\", \"operator\": \">\", \"value\": 1}\n" +
" ],\n" +
" \"logic\": \"AND\"\n" +
" },\n" +
" \"order_by\": [\n" +
" {\"field\": \"users.name\", \"direction\": \"ASC\"}\n" +
" ],\n" +
" \"limit\": 10,\n" +
" \"offset\": 0\n" +
"}";
JSONObject json = JSONObject.parseObject(jsonString);
String sqlQuery = JSONToSQL.jsonToSQL(json);
System.out.println("Generated SQL Query: " + sqlQuery);
// 验证生成的SQL语句是否正确
String expectedSQL = "SELECT users.name, users.email, COUNT(*) AS post_count FROM users " +
"INNER JOIN posts ON users.id = posts.user_id AND users.status = posts.status " +
"WHERE (users.age > 21 AND users.status = 'active') " +
"AND (users.name = 'Alice' OR users.name = 'Carol') " +
"GROUP BY users.name, users.email " +
"HAVING post_count > 1 " +
"ORDER BY users.name ASC " +
"LIMIT 10 OFFSET 0;";
assertEquals(expectedSQL, sqlQuery);
// 执行生成的SQL查询
ResultSet rs = stmt.executeQuery(sqlQuery);
// 验证查询结果
assertTrue(rs.next());
assertEquals("Alice", rs.getString("name"));
assertEquals("alice@example.com", rs.getString("email"));
assertEquals(2, rs.getInt("post_count"));
assertTrue(rs.next());
assertEquals("Carol", rs.getString("name"));
assertEquals("carol@example.com", rs.getString("email"));
assertEquals(2, rs.getInt("post_count"));
assertFalse(rs.next());
}
}
六、在Idea工具运行代码
将代码复制到Idea,直接运行成功。绝大部分程序员应该是做不到的。
我们也可以进一步让大模型优化一些细节,比如校验JSON参数是否符合规范、生成更大的数据集进行测试、生成更复杂的测试用例等等;
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。