1.MinDoc 简介
2.Scroll源码解析
MinDoc 简介
MinDoc是源码一款面向IT团队的简洁文档管理系统。
它源自SmartWiki文档系统,源码起初基于PHP的源码laravel框架构建,但考虑到PHP部署的源码复杂性,后改用Golang开发,源码便于用户部署与操作。源码获取地址源码
开发初衷是源码为了满足公司IT部门对简单实用的项目接口文档管理和分享的需求。其功能与界面借鉴了kancloud。源码
MinDoc可用于存储日常接口文档、源码数据库字典、源码手册说明等资料,源码内置项目、源码用户、源码权限管理功能,源码适合大部分中小团队文档管理。源码
欲知更多,请访问演示站点、文档、开发与维护信息。源码高亮显示
感谢lifei创造与维护MinDoc。由于精力有限,自年3月日起,Mindoc移交给社区维护,欢迎热心开发者加入。
遇到问题,请提出Issues,加入QQ群讨论。
对开发感兴趣的读者,请关注开发动态。
安装与使用说明如下:
需在服务器上设置环境变量ZONEINFO,值为MinDoc目录下的/lib/time/zoneinfo.zip。
获取更多帮助,请查阅使用手册。
对于无Golang经验的用户,推荐从github下载编译完成的程序。
有Golang开发经验的用户,建议通过编译安装,tp源码加密要求Golang版本不低于1..1,推荐使用1..1。
注意:CentOS7的GLibC版本较低,常规编译版本可能无法使用。需要自行源码编译或使用musl编译版本。
常规编译安装步骤包括:
确保数据库配置在项目目录下的conf/app.conf中正确填写,对于MySQL,配置编码为utf8mb4_general_ci。
若使用SQLite,直接配置数据库路径。
若conf目录下无app.conf,请将app.conf.example重命名为app.conf。
默认生成超级管理员用户:admin,初始密码为,请登录后修改。
在Linux系统中,无需依赖gLibC。使用musl-gcc编译Mindoc。影视源码社区
对于Docker用户,参考内置Dockerfile文件编译镜像。
启动镜像时需提供常用环境变量,详情参考conf/app.conf.example文件。
使用编辑器如Editor.md与wangEditor进行Markdown与富文本编辑。
项目功能还包括项目创建、列表、概述、成员、设置与预览。
欢迎在MinDoc项目的GitHub上报告问题或提出改进方案。
如需了解GitHub Fork和Pull请求模式,请参阅GitHub文档。
作者lifei,非纯PHP开发者,非自由gopher。
Scroll源码解析
1. Scroll查询在指定_doc排序时相较于不指定排序或指定某个字段排序能明显更快,这是源码自动同步由于Scroll查询的机制及底层实现所致。
首先查看Elasticsearch的Collector,其主要功能是收集文档并按照特定规则排序。其中,TopDocsCollector类在收集文档后会返回一个有序的TopDocs对象,该对象是搜索结果的返回值。TopDocsCollector有三个子类:SimpleFieldCollector、PagingFieldCollector、SimpleTopScoreDocCollector 和PagingTopScoreDocCollector。这些子类根据排序规则(如字段排序、简单排序等)进行文档排序。
2. 对于TopScoreDocCollector,其排序规则是先执行打分,分数相同的文档按文档号排序。TopFieldCollector则是先按照指定字段排序,值相同的文档再按文档号排序。
3. TopScoreDocsCollector的两个子类(SimpleTopScoreDocCollector和PagingTopScoreDocCollector)在功能上区别在于PagingTopScoreDocCollector针对翻页请求,代码上增加了对after的判断。对于使用TopScoreDocsCollector无论是否为翻页请求,每次请求都会扫描全部命中文档并计算分值。使用SimpleTopScoreDocCollector还是PagingTopScoreDocCollector取决于after是否为null。
4. 对于scroll请求,after参数等于scrollContext.lastEmittedDoc,即上次翻页最大的ScoreDoc。TopFieldCollector同样有两个子类(SimpleFieldCollector和PagingFieldCollector),其判断逻辑与TopScoreDocsCollector类似,也是根据searchContext.sort()是否为null来决定使用哪类Collector。
5. 在lucene6.4.1版本中,无论是SimpleFieldCollector和PagingFieldCollector都无法提前终止收集过程。然而,从更高版本的lucene开始,具备了提前结束收集的功能,判断依据是search sort=index sort一致时,通过抛出CollectionTerminatedException异常提前结束收集。Elasticsearch从6.x版本开始也支持了自定义写入顺序,可以不是_doc而是某个字段值。
6. 通过Elasticsearch的代码分析,我们确认scroll请求在指定_doc排序并从第二页开始时,只会收集指定数量的doc,性能表现更优。对于scroll请求,包装了一层MinDocQuery,用于过滤掉已经翻页过的数据,大大减少文档命中数,避免收集无用的doc,这对于深度翻页性能提升明显。
7. 对于scroll请求,由于不支持向前翻页,每次查询对于已查过的数据无需收集。Elasticsearch通过MinDocQuery实现跳跃功能,将doc跳到segmentMinDoc(lastEmittedDoc+1),在合并倒排表之后,实际上就不会再命中上一页的内容。触发提前终止后,后续倒排表合并也不再必要,性能提升显著。
8. Scroll与search_after查询实际上走的是相同的逻辑,都是通过一个after变量进行翻页。scroll的after参数为scrollContext.lastEmittedDoc(ScoreDoc),search_after的after参数为包含sort字段信息的FieldDoc,都是ScoreDoc。最终都会收集全部命中文档才能得到排序结果,但scroll对于_doc排序做了优化,性能表现更佳。
9. 对于search_after查询,即使指定_doc排序,仍然需要收集全部命中文档,因为search_after是动态的,MinDocQuery跳跃功能不适用。然而,search_after在lucene后续版本中支持了提前终止功能,当查询时指定sort为index sort,可以触发提前终止,不再收集全部命中文档。
. Scroll请求保存的上下文信息主要是maxScore和lastEmittedDoc用于翻页,但实际保存的不仅仅是ScrollContext,而是SearchContext,其中包含了更多关键信息,如searcher和IndexReader,后者对于后续索引更新是感知不到的,除非重新打开reader或使用DirectoryReader.openIfChanged(oldreader)。这是Scroll查询无法感知索引更新的原因。
. 经过测试,即使在scroll过程中触发了merge,被merge的segment文件也不会立即被删除,新的segment文件也不会被发现。这表明Scroll查询无法感知数据更新,其本质是快照了LeafReaderContext,并非检索命中的结果。
总结而言,Scroll查询在指定_doc排序时,通过优化收集过程和使用MinDocQuery实现跳跃功能,能显著提升性能,尤其是在翻页操作中。同时,Scroll请求的机制及底层实现使得其在查询处理上与search_after查询存在显著差异,但在Elasticsearch6.x版本中引入了索引预排序和提前终止功能,进一步优化了查询性能。