# tag-based-pkm **Repository Path**: E_wsq/tag-based-pkm ## Basic Information - **Project Name**: tag-based-pkm - **Description**: 基于标签的个人知识库管理系统 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-09-08 - **Last Updated**: 2021-09-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # tbp:基于标签的个人知识库管理系统 ## 动机 作为开发人员,会接触到很多的新知识,需要存储起来,并且在需要的时候检索这些数据进行主题研究,这个过程的载体往往是各种笔记软。 在这个过程中,认知会不断发生变化,原有的体系结构需要进行调整变动,这要求作为载体的笔记能够很方便的调整结构。 现有的笔记软件,大多会提供基于层级目录的文件管理方式,但是这种方式并不灵活。如果一开始没有建立好合适的层级结构,很容易导致笔记内容东一块儿西一块儿,散落的到处都是,因为一个文件具体该怎么分类,也是个不断变动的过程。查找笔记也往往是基于内容进行检索,但是全文检索功能过于强大,会把很多无关紧要的信息拉取出来。 我个人在使用现有笔记软件的时候,随着笔记数量的增大,总会感觉不适应:结构变动不易,检索困难。当然这可能也是我个人的问题,不太会组织内容。 另外笔记软件为了提供强大的功能,往往是把数据以自己的格式存储起来,一旦离开这个软件,这些数据就很难解读出来。对笔记软件越深度的使用,对于这个软件的依赖就越高,最后就很难离开,甚至不能离开。作为程序员,把数据存储在别人手里,不能在感觉不适合的时候切换其他方案,心里还是会有些膈应。 因此我希望的软件满足这些功能: - 层级结构易于变动,可以很轻松的进行调整,不用有太大的心理负担。 文件可以按照多个维度进行分类,轻松进行调整。 - 目的性更强的检索功能,高性能。 基于更加精炼的内容进行检索,用户容易搜索到自己想要的东西 - 所有数据本地存储。数据的同步功能交给其他软件实现。 - 所有资源归用户所有,即使离开这个软件,也最大程度的方便用户的后续使用。 文件的一些操作,可以依赖本地的软件进行,比如对md文件的编辑,可以使用typora或者任何用户喜欢的软件。系统本身只负责元数据的维护,其他的功能交给更适合的软件完成。 - 提供一定程度的其他笔记软件的兼容性,方便用户将其他笔记资源纳入管理 最方便的方式方法就是使用url资源定位,将对应笔记内容的url放入系统管理 在探索的过程中,我接触到了 [dendron](https://github.com/dendronhq/dendron) 这个项目。这个项目试图构建一个个人的知识库管理系统,这个项目基于vscode进行构建,使用层级标签作为核心概念,作者详细描述了自己的知识库探索过程,提及了知识库背后的一些理论,在阅读了他的博客之后,我决定以标签作为系统的核心元数据,为此需要提供基于标签的检索、修改标签、标签批处理功能。 与dendron的作者不同的是,我认为基于vscode太过局限,vscode更多是一个编辑器的功能,可以管理写作的内容,但是知识库的管理内容不应该被限制于文本,应该更加强大;标签之间应该是平等的,可以随意组合的,文件的名称也可以更加有意义一些,进行文件内容的补充说明。 因为是java技术栈,对于前端的东西接触有限,因此最终选择使用spring boot开发javaweb程序。但是为了提供更多的可能,同时也提供了命令行程序,为了能够同时基于命令行和web进行操作数据,将核心功能拆离出来,可以作为jar依赖,也可以独立作为服务启动,通过自定义的tcp协议进行交互。相对而言还是web页面使用较多一些。 在开发过程中,借鉴了zookeeper中的一些设计,包括命令序列化、数据全量增量存储、项目打包构建。 ## 介绍 为本地文件额外维护标签元数据,可以通过标签组合、文件名称快速检索。 特点: - 所有的数据都存储在本地,所有的文件都通过本地软件进行访问、编辑。 - 支持文件、文件夹、url的管理。 - 快速高效:所有元数据在启动时全部加载到内存当中,高速处理 - 可靠:基于增量+全量的元数据存储方式,操作生效便会被立刻持久化,增量的存储方式保证每次持久化操作在几毫秒内完成。 - 简洁:基于二进制存储元数据,每个文件的元数据一般不超过300字节 在之前,我使用过 TagSpaces 这款软件,来尝试管理本地的资源。这个软件通过修改文件名的方式来添加标签,可以预览文件的内容。但是当文件变多之后,软件会比较卡顿,而且使用文件名的方式维护标签也并不合适,效率并不好。作为程序猿,会维护很多零零碎碎的文档,一旦数量上来,这个软件就遭不住了。 操作系统自身并没有为维护额外标签元数据的功能,为此只能尝试别的办法,将元数据维护在文件之外,然后建立两者之间的关系。最好的联系方式就是通过文件地址来作为文件的唯一标识。这就要求用户不能绕过系统来修改文件的名称、路径信息。但是我认为这么做是值得的,可以大大降低系统维护的难度,而且相较于路径,调整标签显然更加方便。用户在使用系统的时候,应该尽量忽略文件的实际存储路径,而关注于标签信息。 但是有的时候还是需要访问文件所在位置,然后进行一些操作的,所以提供了“打开文件所在位置并选中文件”的功能。 系统中定义的本地资源可以非常灵活。资源可以是md文件,可以是图片,office文档,文件夹,也可以是url地址(为了让url离开系统也能使用,url被存储为本地的html跳转页面)。 不同的文件可能有不同的本地化的操作需要,比如美化图片、编辑md文件。tbp系统不打算承担这部分的内容,这些事情应该交给更加适合的软件去做。后续会开放插件接口,可以根据自己的需要,定制针对特定文件的处理逻辑。 文件名作为对文件内容的描述,也有非常重要的地位,因此用户可以自己修改文件名(需要通过系统修改),文件名会作用到实际的文件名上。同时系统提供了通过正则表达式来检索文件名的功能。 为了提高检索的效率,tbp系统在启动时把所有的元数据加载到内存当中,查询、修改操作可以在几毫秒内返回结果。修改操作会立刻落地磁盘,避免数据丢失。为了节省存储空间,文件的元数据采用二进制存储,500个文件的元数据占用不到90kb的存储空间。 ## 模块介绍 tbp-assembly:项目打包模块 tbp-cli:命令行客户端 tbp-common:model、常量类、操作类 tbp-genertor:解析自定义dsl文件,生成model类。 tbp-core:核心jar tbp-nio:tbp的tcp客户端、服务端实现 tbp-web:spring boot模块 ## 打包 拉取代码,在项目根目录下执行 ``` mvn clean package ``` 命令会在tbp-assembly下的target中创建`tbp-1.0-SNAPSHOT-bin.tar.gz`文件。 ## 运行 将打包阶段构建的压缩文件放置到合适路径下解压。 ``` ├─bin │ tbpCli.cmd # tcp client启动命令 │ tbpEnv.cmd │ tbpServer.cmd # tcp server启动命令 │ tbpWeb.cmd # web项目启动命令 │ ├─conf │ application.yml # web项目配置文件 │ log4j2.xml # tcp模式下的服务端日志配置 │ tbp.cfg # tcp模式下服务端配置 │ ├─lib # tcp、cli依赖lib │ gexf4j-1.0.0.jar │ guava-18.0.jar │ jansi-1.18.jar │ jline-3.16.0.jar │ jline-builtins-3.16.0.jar │ jline-console-3.16.0.jar │ jline-reader-3.16.0.jar │ jline-style-3.16.0.jar │ jline-terminal-3.16.0.jar │ log4j-api-2.13.3.jar │ log4j-core-2.13.3.jar │ log4j-slf4j-impl-2.13.3.jar │ picocli-4.5.2.jar │ picocli-shell-jline3-4.5.2.jar │ slf4j-api-1.7.25.jar │ stax-api-1.0-2.jar │ stax2-api-3.1.4.jar │ tbp-cli-1.0-SNAPSHOT.jar │ tbp-common-1.0-SNAPSHOT.jar │ tbp-core-1.0-SNAPSHOT.jar │ tbp-nio-1.0-SNAPSHOT.jar │ woodstox-core-asl-4.4.1.jar │ └─web # web独立jar tbp-web.jar ``` ### web模式启动 #### 配置 修改`conf/application.yml`中的配置。一般只需要修改snap和store两个配置就可以 ```yaml tbp: # 元数据存储目录 snap-dir: D:\\pkm\\snap # 文件存储目录 store-dir: D:\\pkm\\store ``` #### 启动 进入bin目录,调用`tbpWeb.cmd`。mac用户可以执行`cat tbpWeb.cmd|sh`启动 #### 使用 访问,其中端口号是application.yml中配置的`server.port`参数 ### tcp模式启动(web+cli) tcp模式主要是为了cli、web同时操作而开发的。提供命令行操作,可以为系统提供更多可能性,有些批量处理操作,通过命令行会更加便捷。 > 原本的cli交互需要启动tbpServer,通过nio进行交互,但是觉得有点多此一举,因此提供了直接访问web接口的方法。 > > 需要首先启动tbpServer,作为nio服务器接受请求。web客户端会将接受的请求,通过nio发送给tbpServer来获取数据。cli客户端会把用户的命令发送给tbpServer,每个命令都会创建tcp连接与tbpServer交互。 > > nio的代码依然保留,但是不再启用。 ![](http://assets.processon.com/chart_image/60b857f51e08537af3d633b3.png) 现在的交互模式: cli通过feign远程调用web接口的方式提供服务。 feign interface和对应的feign controller通过代码自动生成,降低维护成本。 #### 配置 和web模式配置相同,只要设置好`application.yml`文件就可以 #### 启动 为了操作方便,推荐将`bin`目录加入环境变量,这样可以直接进行操作,而不用进入目录下进行交互。 启动tbpWeb服务 ``` tbpWeb ``` #### 使用 web: 访问,其中端口号是application.yml中配置的`server.port`参数 cli:具体的命令内容,可以通过输入` -h` 查看帮助 ``` tbp-file:资源操作指令 tbp-tag:标签操作指令 ``` ## 使用建议 ### chrome app 使用chrome app,把安装成本地应用,可以避免和其他web页面混合在一起 ### 数据同步 系统的数据全部存储在snap、store目录中,只要将数据同步到其他设备上,就可以在其他设备上继续工作。 我个人使用的是 坚果云 进行数据同步,在win和mac上使用。 ## 性能测试 所有元数据存储在内存当中,标签使用set集合存储,保证匹配效率。在使用标签+文件名正则 查询时,系统会优先使用标签过滤数据,然后再进行正则匹配。只有在单独只用正则查询时效率会低下一些。 使用mac m1 pro,16G版本,基于jmh的微基准测试,在系统存储100w数据时,产生150M左右数据,每次启动需要花费7s左右加载数据。基于标签的查询,每次查询在毫秒内完成。使用正则匹配,单次查询需要2s~3s左右,但是一般不会仅仅基于文件名查询,还会使用标签来过滤数据,不会让正则直接检索百万数据,所以实际使用时应该不需要担心正则匹配的效率问题。 - 测试数据生成类:`com.sayyi.software.tbp.core.PkmPerformanceTest` - 微基准测试类:`com.sayyi.software.tbp.core.PerformanceTest` 个人觉得,应该是不需要担心性能问题。 ## 升级 系统升级时,可能修改数据格式,因此每次升级之前,需要提前处理元数据。 1. 使用原版本,重启一次服务端。这会将增量数据添加到全量快照文件中。 2. 备份snap中的元数据。主要是避免升级失败,需要重新恢复数据。 3. 删除snap中的request文件。 4. 使用新版本启动。系统会自动将全量数据的格式升级成新版数据,之后就可以正常使用了。 ## 使用心得 工具终究是辅助,最重要的还是自我在过程中的收获。在使用这个过程中,用户需要自己来提取文件的核心内容,用标签作为载体进行记录。用户需要自己决定使用哪些标签,每个标签代表何种含义。随着用户自己的经验增长,会发现原有设计不合适的地方,这个修改的过程应该是成长过程中的常态,在基于标签的检索系统中,标签只是一串字符串,修改起来非常容易,不需要有太大的心理压力。 基于标签还有一个好处,应该是用户可以更加容易针对某些主题进行研究,比如对 心跳机制 感兴趣,那么可以通过这个标签,获取所有涉及 心跳机制 的文件资源。 左侧的标签虽然是树状的,但是仅仅只是展示形式,标签之间的关系应该是平等的。 除了主动检索文件之间的联系,我还希望能够有被动一点的方式,比如通过图形来展示标签之间的联系。但是具体怎样还是在探索过程中。 经验的丰富是一个主动的过程,离不开主动的思考,想要借助某个工具一劳永逸是不现实的,还是要自己多思考、多尝试。 这个系统的核心在于用户主动提炼文件的标签信息,然后根据这些信息来查阅文件。文件应该使用什么标签来进行提炼,检索时选择哪些标签,是使用系统的核心。标签体系的建立,需要用户自己主动思考,系统只是帮助方便的达成目的。用户不应该被系统的功能所束缚,如果在使用过程中有任何问题,欢迎给出意见、建议。 ## 后续功能设想 - [ ] 通过插件的方式,来支持更多的文件操作。 - [ ] 更复杂的标签语法,比如存在某些标签但是没有另外一些标签、或关系的标签查询。