You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apache Nutch以job文件集群运行时无法读取自定义配置文件问题

问题背景

我已完成Apache Nutch 1.x的网页爬取相关配置,根据业务需求,需要为每个被索引的域名向Solr文档添加额外信息,该部分配置存储在JSON文件中。我基于index-basic插件完成了对应功能开发,在本地模式下测试运行成功,插件初始化代码片段如下:

this.enable_extra_domain  = conf.getBoolean("domain.extraInfo.enable", false);
if (this.enable_extra_domain) {
     String domainExtraInfo = conf.get("domain.extraInfo.file","conf/domain-extra.json");
     readDomainFile(domainExtraInfo);
     LOG.info("domain.extraInfo.enable is enabled. Using " + domainExtraInfo + " for input.");
}
else {
    LOG.info("domain.extraInfo.enable is disabled.");
}

负责读取配置文件的函数实现如下:

private void readDomainFile(String domainExtraInfo) {
    // Instance of our Domain map with extra info
    website_records = new HashMap<String, List<Object>>();
    
    JSONParser jsonParser = new JSONParser();
    try (FileReader reader = new FileReader(domainExtraInfo))
    {
        Object obj = jsonParser.parse(reader);
        JSONArray DomainList = (JSONArray) obj;
  
        DomainList.forEach( domain -> parseDomainObject( (JSONObject) domain ) );
        
    }
    catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
}

上述代码在本地模式下运行完全正常,但当我将Nutch打包为.job文件提交至EMR(或其他Hadoop集群)运行时,抛出java.io.FileNotFoundException异常。本地运行时新增的配置文件存放在conf目录下,集群部署时该配置文件已被打包进.job文件中。

问题根因

核心问题是FileReader只能读取本地文件系统上的物理磁盘文件,无法读取JAR包(Nutch生成的.job文件本质是可执行Hadoop作业JAR)内部的classpath资源。
本地运行时,Nutch直接从项目本地磁盘的conf目录读取实体文件,路径匹配所以可以正常加载;提交到集群运行时,.job文件会被分发到各个计算节点的工作目录,代码中写的相对路径conf/domain-extra.json会被解析为节点本地磁盘上的路径,而非JAR包内部的资源路径——哪怕文件确实被打进了JAR包,FileReader也无法穿透JAR包读取内部文件,因此抛出文件不存在异常。

解决方案

你可以根据自身业务场景选择以下任意一种方案解决:

  • 方案1:改用Classpath读取资源(最推荐,无需改动现有部署流程)
    替换readDomainFile方法中的文件读取逻辑,通过类加载器获取JAR包内的资源流,不再依赖本地文件路径读取,修改后的代码示例:
    private void readDomainFile(String domainExtraInfo) {
        website_records = new HashMap<String, List<Object>>();
        JSONParser jsonParser = new JSONParser();
        // 从classpath读取资源流,兼容本地运行和集群JAR包运行场景
        try (InputStream is = getClass().getClassLoader().getResourceAsStream(domainExtraInfo))
        {
            if (is == null) {
                throw new RuntimeException("Domain extra config file not found in classpath: " + domainExtraInfo);
            }
            try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
                Object obj = jsonParser.parse(reader);
                JSONArray DomainList = (JSONArray) obj;
                DomainList.forEach( domain -> parseDomainObject( (JSONObject) domain ) );
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to load domain extra config", e);
        }
    }
    
    注意:使用该方式时请确认打包后JSON文件在JAR包内的相对路径和domain.extraInfo.file配置值一致:如果文件打在JAR包的conf/目录下,保留原有conf/domain-extra.json配置即可;如果文件被打在JAR包根目录,将配置值改为domain-extra.json即可。
  • 方案2:通过Hadoop分布式缓存分发配置文件
    如果后续需要频繁修改JSON配置、不想每次调整配置都重新打包Nutch作业文件,可以在提交作业时将配置文件加入分布式缓存:
    1. 将domain-extra.json上传到HDFS固定路径
    2. 提交Nutch作业时添加分布式缓存参数,将HDFS上的配置文件分发到所有计算节点的本地工作目录
    3. 代码中直接读取缓存到本地的文件即可,无需修改原有文件读取逻辑,但需要额外配置作业提交参数
  • 方案3:将配置直接写入Nutch配置文件
    如果JSON配置内容较小且基本不会变动,可以直接将配置内容转义后写入nutch-site.xml,代码中直接从Nutch的Configuration对象读取配置值解析,完全不需要依赖独立文件,稳定性最高但灵活性较差。

内容的提问来源于stack exchange,提问作者Hafiz Muhammad Shafiq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:24:19