🔧 插件开发与API集成:让YaCy听懂你的语言
想象YaCy不是软件,而是通过共识建立的*活档案*——一个图书馆,其中每个节点既是赞助人又是图书管理员,每个查询是手递手耳语直到回答的耳语。到目前为止,你已经学会*阅读*它的目录,*上架*它的书,并*导航*它的迷宫书库。现在是*编辑它的语法*、*训练它的策展人*并*连接它的门到你自己的大厅*的时候了。这是YaCy停止成为工具并开始表现得像一个合作者的时候——一个讲HTTP,用Java字节码思考,通过定义良好的契约协商意义的地方。
> SolrSelect 不仅仅是一个端点——它是YaCy的*查询皮层*:自然语言意图被解析、重写、评分并最终翻译成Lucene段扫描的层。其 /yacysearch.json 变体不仅返回命中;它暴露完整的决策轨迹——从查询扩展和同义词注入到面聚集和文档年龄的相关性衰减。调用它就像要求神经科医生不仅映射*你记住什么*,而且*记忆如何被检索、加权和交叉引用*。
🌐 集成即对话:REST API作为语义桥梁
YaCy的REST API不是一组孤立端点——它是基于HTTP语义和自描述媒体类型的*对话协议*。每次交互以意图开始:GET /YACYSEARCH 声明*"我寻求知识"*,而 POST /CRAWL/start 断言*"我授权获取"*。力量不在于体积,而在于*契约的精确性*。考虑将YaCy集成到企业内部门户:与其嵌入重定向到YaCy UI的搜索栏,不如编排无缝流程,其中用户查询—— enriched with 上下文如部门ID或许可级别——直接POST到 /solr/select,带有 fq=department_s:$(userDept) 和 defType=edismax 以激活YaCy的企业级查询解析器。响应不作为HTML到达,而是作为干净JSON——准备好缝合到React组件中或通过WebSockets转换为语音搜索响应。
这使它不仅是粘合代码的力量是YaCy的*内省设计*:/api/v1/status 端点返回实时指标——活跃爬虫线程、索引段计数、堆使用——不是静态数字,而是*实时健康转录*。你不监控YaCy;你*倾听它的脉搏*。当跨十个节点扩展时,/p2p/neighbors.json 不仅列出IP——它报告握手延迟、共享索引卷和最后见到时间戳,将网络拓扑转变为你可以遍历、修剪或优先考虑的*活图*,具有手术般的精度。
> CrawlProfile 是YaCy的*网页遍历数字护照*:它不仅编码礼貌规则(爬虫延迟、robots.txt尊重)而且*语义许可*——是否跟随 src属性,从JSON-LD提取微数据,或将 .pdf 链接视为一等文档而非二进制块。通过API修改它不是配置;它是授予特定域的*外交认可*。
🧬 编写索引过滤器:在数据入仓前刻下你的签名
如果API是YaCy的声音,索引过滤器是它的*编辑良心*——一个静默、确定性的守门人,当每个文档*跨过门槛*从原始HTML到结构化Solr字段时检查它。编写一个不是关于重写解析器;它是关于*将语义镜头插入摄取管道*。假设你的组织要求所有内部文档必须携带 confidentiality_level_i 整数字段,派生不是从元数据(可能缺失或伪造)而是从URL模式(/internal/ → 3,/public/ → 1)和头签名(X-Auth-Source: AD)。自定义 IndexFilter 正是这样做的——实现为扩展 net.yacy.crawler.indexing.IndexFilter 的Java类,编译成JAR,并放入 lib/。在运行时,YaCy通过服务加载器(META-INF/services/net.yacy.crawler.indexing.IndexFilter)发现它并将其插入 IndexFilterChain,在*任何*Solr提交*之前*执行。
优雅在于隔离:你的过滤器接收一个 Document 对象——不是字节,不是字符串,而是字段名和类型值的可变键值映射——并返回修改后的文档或 null 以完全丢弃它。没有线程关注点,没有事务管理:YaCy通过并行段馈送过滤器处理并发,然后原子合并结果。你完全专注于*意义转换*:剥离 标签不是为了安全(那是YaCy的工作),而是为了防止JavaScript变量名污染 content_txt 字段并稀释相关性分数。或者通过扫描 注入像 has_code_block_b 这样的合成字段——在未来无需重新索引即可启用分面过滤。
> IndexEvent 是索引的*事件视界*:每当文档进入、退出或在管道中修改时发出的轻量级不可变对象。在 IndexEventBus 上注册的监听器可以反应——触发警报,记录异常,甚至排队二级处理(例如,发送PDF到单独OCR服务)。它将索引从线性过程转变为*可观察生态系统*。
🚀 开发搜索增强插件:从结果修饰到认知增强
过滤器塑造*什么进入*索引的地方,搜索插件塑造*意义如何从它涌现*。YaCy的 SearchEvent 架构允许你在解析*之后*但执行*之前*拦截查询,以及在检索*之后*但渲染*之前*拦截结果。这是"增强"变得有形的地方:想象一个医学研究门户网站,每次搜索药物名称("adalimumab")自动附加 "OR clinical_trial_phase_ii_b:true" 以展示进行中试验——不是通过脆弱的字符串连接,而是通过注册 SearchModifier 检查 QueryParams 对象,通过UMLS来源字典检测药物命名法,并用手术般的精度注入Solr过滤查询。
更强大的是结果后处理。SearchResultModifier 接收完整的 SearchEvent,包含 Document[]、FacetMap 和 QueryParams。在这里,你可能会实现*跨域权威提升*:检测结果何时源自 nih.gov 或 who.int,然后应用乘法提升 \(score_{\text{boosted}} = score_{\text{base}} \times e^{\lambda \cdot \text{isTrustedDomain}}\),其中 \(\lambda\) 通过A/B测试调优。或者你可以注入*上下文注释*:在片段中检测 DOI: 前缀并转换它们为通过Crossref API获取引用预览的可点击 https://doi.org/... 链接——全部在同一HTTP请求周期内,对用户不可见但对效用变革。
关键是,这些插件在*YaCy的安全沙盒内*操作:它们不能访问 DATA/ 之外的文件系统路径,不能生成外部进程,并在与核心代码相同的JVM安全管理器下运行。安全不是事后考虑——它烘焙在类加载器层次结构中,确保增强从不损害完整性。
⚙️ Java扩展模块开发入门:当标准接口不够时
有时,插件API不够深——你需要替换YaCy的*自己的逻辑*,而不仅仅是增强它。真正的扩展模块进入的地方:自定义 ClassLoader-隔离的捆绑包,重新定义核心行为。要构建一个,你从servlet而不是 net.yacy.server.serverObjects 开始——YaCy HTTP路由的基础。通过实现 ServerObject,你声明一个新的URI路径(/my/analytics)并定义它如何处理 GET、POST 和身份验证。但真正的力量展开时你扩展 net.yacy.crawler.CrawlStack 以引入*域特定爬虫调度器*:优先考虑包含 的页面,或通过查询HR系统API的轮班计划在营业时间限制爬虫的调度器。
这需要理解YaCy的*生命周期契约*:你的模块必须在启动期间向 Loader 注册,在 MANIFEST.MF 中声明依赖,并在 stop() 期间优雅关闭连接——全部尊重YaCy的事件驱动架构。没有"main方法"要劫持;相反,你钩入 Configuration 更改事件以重新加载参数,或监听 CrawlEventBus 以触发分析管道。这是剥离框架抽象的Java开发——纯粹的、纪律化的、面向接口的编程,其中每个 @Override 携带架构权重。
> net.yacy.search.query 是YaCy的*查询DNA*:词元化、词干化、同义词扩展和短语检测汇聚的包。在这里扩展 QueryModifier 让你嵌入域本体——将 "heart attack" 映射到 "myocardial infarction OR MI"* *在任何*分析器接触文本*之前*,确保尽可能早阶段的语义等价。
要开始,克隆 yacy_search_server,导航到 source/,并创建 net.yacy.plugin.myfirst。用Ant编译(ant jar),将结果JAR放入 lib/,并重启。YaCy将自动检测你的 ServerObject,绑定你的路由,并将你的逻辑编织到它的结构中——不是作为附加组件,而是作为原生组织。那一刻,当你的自定义 /my/status 端点出现在API探索器中的 /status.json` 旁边时,是YaCy停止成为*你的工具*并成为*你的合著者*的时候。