2024年4月

算法1:用于判断一个字符串的字符是否都是唯一的,即没有重复的字符。

解决思路:首先将输入的字符串转换为字符数组,然后对字符数组进行排序。之后,使用一个while循环遍历排序后的字符数组,如果发现有任何两个相邻的字符相同,则返回false,表示字符串中有重复的字符。如果循环结束后都没有发现相邻的字符相同,则返回true,表示字符串中的字符都是唯一的。

代码示例:

 public booleanisUnique(String astr) {char[] chars =astr.toCharArray();
Arrays.sort(chars);
int i=0;while(i<chars.length-1){if(chars[i]==chars[i+1]){return false;
}
i
++;
}
return true;
}

上面潜在问题与风险:

字符编码问题:此方法假设所有字符都可以使用char类型处理,这对于大多数ASCII和Unicode字符是有效的。但是,如果处理包含如中文、希伯来文等复杂脚本的字符串时,单个字符可能需要多个char来表示(Java中的String和char基于UTF-16编码,对于代理对这种情况需要特殊处理)。这可能不是您想要的行为,尤其是在处理全球化的应用程序时。
性能效率问题:该方法对字符串进行排序,这在字符串非常长时可能非常耗时。对于判断字符串是否唯一的目的,排序并不是最高效的方法,因为它的时间复杂度是O(nlogn)。
空间复杂度问题:转换字符串为字符数组并进行排序将需要额外的O(n)空间复杂度,这在某些内存受限的场景下可能不是最佳选择。
异常处理:方法中没有对输入参数astr进行空值检查。虽然Java中对空字符串进行排序不会抛出异常,但如果业务逻辑不允许空字符串的存在,应当显式检查。
优化方向
使用HashSet:一个更高效的方法是使用HashSet。HashSet是一个无序、不重复元素的集合,它的添加操作的时间复杂度接近O(1)。可以通过遍历字符串的每个字符,尝试将它们添加到HashSet中来判断字符是否重复。如果字符重复,HashSet会拒绝添加,并立即返回false。这种方法的时间复杂度接近O(n),且不需要额外排序,更高效。
检查字符串长度:可以通过直接检查字符串的长度和字符集的大小来快速判断字符串是否包含重复字符。例如,如果字符串长度大于字符集的大小(考虑Unicode,这个字符集大小是固定的,即Character.MAX_VALUE),则一定存在重复字符,可以直接返回false。这种方法可以提前终止一些不必要的检查,尤其是在字符串很长时。
不使用额外空间:如果空间复杂度是一个重要考虑因素,可以通过遍历字符串,使用一个长度为Character.MAX_VALUE的boolean数组来标记字符是否出现过。这样可以将空间复杂度降低到O(1),但会稍微牺牲一些时间复杂度,因为需要额外的逻辑来处理Unicode代理对。
代码可读性:当前方法的实现逻辑较为间接(通过排序来寻找重复),对于未深入了解的读者可能不够直观。使用HashSet或其他直接算法可以提高代码的可读性和可维护性。
安全性和边界条件
安全性:此方法不涉及网络、文件访问或其他外部资源,因此从传统意义上讲是安全的。但是,它依赖于Java String和字符数组的实现,应确保使用的Java环境没有相关安全漏洞。
边界条件:应当检查输入参数是否为null,避免潜在的NullPointerException。同时,空字符串("")应当被认为是不包含重复字符的,这一点当前实现处理得当。
以下是相应的代码优化。请注意,由于涉及的修改较为复杂,一些细节可能需要进一步调整。

根据上述建议,可以使用HashSet来优化原代码,不仅提高性能,同时增强代码的可读性和可维护性。以下是使用HashSet重构后的代码:

1 public classStringUniqueChecker {2     /**
3 * 用于判断一个字符串的字符是否都是唯一的,即没有重复的字符。4 * 使用HashSet来检查字符是否重复,HashSet的add方法会自动拒绝重复的元素。5 *@paramastr 输入的字符串6 *@return如果字符串中的字符都是唯一的,则返回true;否则,返回false。7      */
8     public booleanisUnique(String astr) {9         //检查输入是否为null或空字符串
10         if (astr == null ||astr.isEmpty()) {11             return true;12 }13 
14         HashSet<Character> set = new HashSet<>();15         for (int i = 0; i < astr.length(); i++) {16             char c =astr.charAt(i);17             //如果set中已经包含了当前字符,则说明有重复字符
18             if(set.contains(c)) {19                 return false;20 }21 set.add(c);22 }23         return true;24 }25 }

1. 前言

自从和
员外
上家公司离职后,我们就自己搞公司投入到了RAG大模型的AI产品应用的开发中,这中间有一个春节,前后的总时间大概是三个月左右,在这三个月期间,基本是昼夜兼程啊,到今天3月底结束,产品目前看是有了一个基础的雏形。

在这期间,员外负责整个产品的营销、商业客户的洽谈等方面的内容,我和阿包负责整体的技术架构搭建,代码从0-1的编写,我们是在24年1月26,产品初步上线了一个版本,开始接受企业客户的试用,这让我们接受到了大量的需求,以及我们产品在目前的市场环境中还存在哪些竞争力不足需要改进的地方。

三个月时间过去了,在我们的TorchV AI 产品初步成型之际,和大家分享一下开发RAG、LLM系统以来的一些心得和经验。

2. RAG简介

图1-RAG基础架构

RAG(检索增强生成)名词一开始来源于
2020年
的一片论文《
Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
》,旨在为大语言模型(LLM)提供额外的、来自外部知识源的信息。这样,LLM 在生成更精确、更贴合上下文的答案的同时,也能有效减少产生误导性信息的可能。

可以说在目前大模型井喷的今天,RAG作为一项为密集型知识NLP任务的处理指明了方向,配合AI大模型,让世界发生了翻天覆地的变化,数以万计的开发者都涌入这个赛道,同时竞争。

我们知道LLM目前存在的一些问题和挑战:

我自己理解LLM大模型本质就是一个二进制文件,所有的知识都通过压缩技术全部压缩在一个/多个GB的二进制文件中,最终在获取数据的时候,通过LLM的模型架构,推理能力,将所有的知识信息又生成出来。

  • 在没有答案的情况下提供虚假信息(胡说八道、幻觉)。
  • 模型知识的更新成本、周期、及大模型的通用能力问题(大公司才玩的转)
  • 数据安全和隐私等问题

而RAG技术的出现,正好能有效的缓解目前大模型存在的一些问题,主要表现方面如下:

  • 经济高效的处理知识&开箱即用:只需要借助信息检索&向量技术,将用户的问题和知识库进行相关性搜索结合,就能高效的提供大模型不知道的知识,同时具有
    权威性
  • 有效避免幻觉问题:虽然无法100%解决大模型的幻觉问题,但通过RAG技术能够有效的降低幻觉,在软件系统中结合大模型提供幂等的API接口就可以发挥大模型的重大作用
  • 数据安全:企业的数据可以得到有效的保护,通过私有化部署基于RAG系统开发的AI产品,能够在体验AI带来的便利性的同时,又能避免企业隐私数据的泄漏。

3. RAG技术&架构思考

既然我们知道,RAG作为密集型知识库的处理和大模型配合起来有着天然优势,那么如何做好RAG的开发?

RAG应用的
基础技术核心
是:
让大模型依靠现有的数据(PDF/WORD/Excel/HTML等等)精准的回答用户的问题

这是最基础的功能,同时也是最低要求,任何做RAG领域的AI应用产品,技术层面都需要去突破解决的技术难题。

注意
两个核心
点:


大家好,我是蓝胖子,在涉及到图片或者视频链接时,通常都会提到防盗链,这一节我将会从防盗链的含义到落地,向大家展示如何设计资源的防盗链。

防盗链的含义与作用

防盗链,顾名思义,是为了防止资源被他人窃取而设计的。

通常我们将图片或视频链接存储到obs对象存储上,前端通过服务端返回的图片或视频链接访问obs上对应的资源,那如果这个链接被第三方网站获取到,便能在其网站上直接访问我们的视频或者图片资源。

防盗链的出现就是为了杜绝第三方网站能直接访问我们的视频或图片资源。
让返回的资源链接只能被我们指定的网站进行访问

防盗链方案设计

接着,我以华为云的obs系统 为例, 讲几个关于防盗链的设计方案,供大家参考,

refer指定黑白名单

浏览器在加载静态资源时,会在请求头中加上
Refer
字段,其值为浏览器当前的网址,目的是为了告诉服务器,用户在访问资源之前的位置。

如果第三方网站获盗取到了我们的视频资源,那么在其访问时,Refer就是第三方网站的网址,我们可以在obs上配置reder黑白名单,指定资源让某些网站不允许访问或者对某些网站允许访问。

Pasted image 20240401163901.png

更加灵活的鉴权方式-远程鉴权

除此以外,还有种更加灵活的鉴权方式,通过自定义的代码来判断该访问链接是否允许被访问。在使用obs系统时,为了减少带宽成本,我们将会在obs前面,部署cdn节点,让用户访问的资源能够被缓存到离他比较近的cdn节点上。

通常cdn节点上可以配置对应的访问,例如华为云可以配置远程鉴权的地址,指向自己的服务器鉴权接口,在接口中定义对资源的访问权限,像cloudflare则是可以创建worker,在worker中定义链接的访问权限。

Pasted image 20240401164545.png

鉴权逻辑应该如何写,这里我提供一个比较通用的逻辑,给大家参考下。

在服务端返回给客户端资源在obs上的访问链接时,可以加上该链接的创建时间,在鉴权逻辑里申明一个链接的有效期,根据链接的产生时间和有效期 允许该链接在有效期内允许访问,比如返回给客户端的链接是

https://xxx?ctime=1711962048

ctime 则是链接的创建时间,但是仅仅这样是不够的,第三方网站可以获取到链接后修改ctime字段来修改链接的创建时间,所以我们还需要一个消息认证的机制,保证链接是服务器返回的且没有经过篡改,这里可以用消息认证算法实现。

拿消息认证算法hmac举例,服务器端定义一个只有自己知道的密钥,用该密钥对资源地址进行md5的摘要计算,如下是golang中的hamc的使用逻辑,

key := "hamcsecrete"
    data := "https://xxx?ctime=1711962048"
    hmac := hmac.New(md5.New, []byte(key))
    hmac.Write([]byte(data))
    fmt.Println(hex.EncodeToString(hmac.Sum([]byte(""))))

得到的消息认证码,加入到资源链接的参数中,如下,

https://xxx?ctime=1711962048&token=679f5d6f7d344dba1e33938ae1d41ab4

这样,鉴权服务器在得到资源链接时,就会将资源地址通过同样的消息认证算法和密钥计算token值,如果计算出的token值和资源链接中的token值一致,则继续查看链接是否在有效期范围内,在则允许访问,否则不允许访问。因为消息认证的密钥只有服务器知道,即使第三方网站获取到了链接,也无法得出正确的token值。

最后,在使用此逻辑的时候,要注意cdn服务器回源的条件,通常cdn是根据url路径查看是否需要回源,如果url地址不同,则会去访问源站服务器,我们当然不希望因为链接ctime的不同就再次去请求源站服务器,所以,在cdn节点处,需要配置,判断回源时需要忽略ctime和token的参数。


k-均值聚类算法(英文:k-means clustering)

定义:
k-均值聚类算法的目的是:把n个点(可以是样本的一次观察或一个实例)划分到k个聚类中,使得每个点都属于离他最近的均值(此即聚类中心)对应的聚类,以之作为聚类的标准。

案例——区分好坏苹果(有Key)

import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import numpy as np

# 生成随机样本数据
# 假设你采集数据是二维的,每个样本有两个特征  [光泽, 气味]
appleData = np.array([[44, 40], [60, 45], [59, 70], [65, 80], [50, 50],
                      [75, 65], [45, 52], [64, 75], [65, 70], [53, 45]])

# 将样本分成2类 : 好果、坏果
# 设置两个初始簇中心的位置,指定Key值
initial_centroids = np.array([[40, 20], [70, 80]])

# 创建KMeans对象,并指定初始簇中心位置
kmeans = KMeans(n_clusters=2, init=initial_centroids)
kmeans.fit(appleData)

# 获取每个样本的类别
labels = kmeans.labels_

# 提取聚类中心
centroids = kmeans.cluster_centers_

# 绘制散点图并着色
colors = ['g', 'r']
for i in range(len(appleData)):
    plt.scatter(appleData[i][0], appleData[i][1], color=colors[labels[i]])

# 绘制聚类中心
for c in centroids:
    plt.scatter(c[0], c[1], marker='x', s=150, linewidths=5, zorder=10)

# 添加标签和标题
plt.xlabel('Glossiness')
plt.ylabel('Smell')
plt.title('Apple glossiness and smell K-Means clustering results')

# 显示图形
plt.show()

show

案例——自动聚类(无Key)

import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import numpy as np

# 生成随机样本数据
X = np.array([[60, 75], [59, 70], [65, 80], [80, 90], [75, 65],
              [62, 75], [58, 68], [52, 60], [90, 85], [85, 90],
              [70, 75], [65, 70], [55, 65], [75, 80], [80, 85],
              [65, 75], [60, 70], [55, 60], [95, 95], [90, 90]])

# 将样本分成3类
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)

# 获取每个样本的类别
labels = kmeans.labels_

# 提取聚类中心
centroids = kmeans.cluster_centers_

# 绘制散点图并着色
colors = ['r', 'g', 'b']
for i in range(len(X)):
    plt.scatter(X[i][0], X[i][1], color=colors[labels[i]])

# 绘制聚类中心
for c in centroids:
    plt.scatter(c[0], c[1], marker='x', s=150, linewidths=5, zorder=10)

# 添加标签和标题
plt.xlabel('Glossiness')
plt.ylabel('Smell')
plt.title('Apple glossiness and smell K-Means clustering results')

# 显示图形
plt.show()

show

1.环境

处理器:飞腾D2000/8 E8C

内存:16GB

系统:银河麒麟桌面版操作系统(国防版)V10

达梦数据库:dm8_20231226_FTarm2000_kylin10_sp1_64

2.软件下载

链接:
https://www.dameng.com/list_103.html

3.环境部署

我这里已经下载好了(软件、环境部署脚本),需拷贝至桌面运行no1.sh,安装完成后运行no2.sh,有需要的同学@我(zuijiaz@outlook.com)

点击桌面,鼠标右键【打开终端】

运行no1.sh

脚本会自动创建数据库账户(dmdba),需要手动设置密码:
字母+数字+符号

等待弹出安装界面

4.数据库安装

图形化界面启动成功后,将弹出【选择语言与时区】页面,默认为简体中文和中国标准时间.

点击【确定】后,弹出 DM 数据库安装程序。

点击【下一步】后,为许可证协议页面,选择【接受】。

点击【下一步】后,弹出 key 文件页面,点击【浏览】选择【key 文件】,若
没有 key 文件
可以直接点击【下一步】,跳过该步骤。

点击【下一步】后,弹出选择组件页面,建议选择
典型安装
,也可根据需要,选择服务器安装、客户端安装和自定义安装。

点击【下一步】后,弹出选择安装位置页面,可点击【浏览】选择安装位置,
/home/dadba/dmdbms

点击【下一步】后,弹出确认安装信息页面,检查安装信息是否准确,确认无误后点击【安装】。

安装时间较久,45分钟以上

5.数据库初始化

安装数据库安装完成后,会弹出选择是否初始化数据库页面,选择【初始化】。

点击初始化后会弹出数据库配置助手,通过数据库配置助手便可以配置数据库。

进入创建数据库页面的创建数据库模版页签,此处可以根据实际需求选择合适的数据库模板,一般建议选择【一般用途】其它保持默认即可,如下图所示:

本例中数据库安装路径为 /home/dmdba/dmdba/data,如下图所示:

可自定义输入或保持默认数据库名称、实例名、端口号等参数,如下图所示:

此处可选择自定义或保持默认配置路径,如下图所示:

此处配置可根据实际需求进行配置,如下图所示

需要注意的是页大小 、簇大小 、大小写敏感 、字符集 、VARCHAR 类型以字符为单位、空格填充模式等部分参数, 一旦确定无法修改 ,需谨慎设置。

常见参数说明:

数据文件使用的簇大小:默认值 16,可选值: 16、 32、 64,单位:页。

数据页大小:默认值 8,可选值: 4、 8、 16、 32,单位: KB。

日志文件大小:默认值 256,单位为: MB,范围为: 64 MB~2 GB。

大小敏感:默认值 Y,可选值: Y/N, 1/0。

字符集:默认值 0,可选值: 0[GB18030], 1[UTF-8], 2[EUC-KR]。

此处选择默认配置即可,
默认口令与登录名一致
,如下图所示:

此处建议勾选创建示例库
BOOKSHOP

DMHR
,作为测试环境,如下图所示:

在安装数据库之前,将显示用户通过数据库配置工具设置的相关参数。点击【完成】进行数据库实例的初始化工作,如下图所示:

安装【完成】

6.设置数据库启动项

运行no2.sh

7.检测数据库是否正常使用

安装包和附件有1G,没有上传,有需要的同学@我。

#The write:zuijiaz@outlook.com
#Time of creation:2024.4.2