🔧 插件开发与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尊重)而且语义许可——是否跟随 <iframe> 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通过并行段馈送过滤器处理并发,然后原子合并结果。你完全专注于意义转换:剥离 <script> 标签不是为了安全(那是YaCy的工作),而是为了防止JavaScript变量名污染 content_txt 字段并稀释相关性分数。或者通过扫描 <pre><code> 注入像 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 以引入域特定爬虫调度器:优先考虑包含 <meta name="priority" content="high"> 的页面,或通过查询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"* *在任何*分析器接触文本*之前*,确保尽可能早阶段的语义等价。
要开始,克隆 yacysearchserver,导航到 source/,并创建 net.yacy.plugin.myfirst。用Ant编译(ant jar),将结果JAR放入 lib/,并重启。YaCy将自动检测你的 ServerObject,绑定你的路由,并将你的逻辑编织到它的结构中——不是作为附加组件,而是作为原生组织。那一刻,当你的自定义 /my/status 端点出现在API探索器中的 /status.json` 旁边时,是YaCy停止成为你的工具并成为你的合著者的时候。