zoukankan      html  css  js  c++  java
  • CDH离线数据导入solr:利用MapReduceIndexerTool将json文件批量导入到solr

    场景描述:前段时间,将实时数据通过kafka+flume+morphline的方式接入到solr中。新进来的数据已经可以在solr中看到了,但是以前的历史数据还没有导入solr。

    CDH提供利用MapReduceIndexerTool来将HDFS的数据导入到solr。

    历史数据格式类似如下按年/月/日保存在HDFS上每天一个文件:

    -/user/data/2016

    -11

      -1

        -data.txt

      -2

        -data.txt 

    -12

       -1

        -data.txt

       -2

        -data.txt

    文件的格式为一行一行的json。

    思路:

    先对2016目录下的所有子目录遍历文件,

    再对文件进行批量的索引操作。

    使用命令:(jar包在/opt/cloudera/parcels/CDH/jars下)

    hadoop jar search-mr-1.0.0-cdh5.8.0-job.jar org.apache.solr.hadoop.HdfsFindTool  -find hdfs://cdh-master/user/kafkadata/eventCount/2016/11  -type f | sudo -u xuyali hadoop --config /etc/hadoop/conf.solrindexer/  jar search-mr-1.0.0-cdh5.8.0-job.jar  org.apache.solr.hadoop.MapReduceIndexerTool --log4j log4j.properties  --morphline-file morphline.conf --zk-host cdh-master:2181/solr --collection event_count_records  --output-dir hdfs://cdh-master/user/hdfs/test/ --verbose --go-live  --input-list -

    参考:cdh官方文档——batch indexing solr

    *注意:官方文档中用的配置是mapreduce1,可以用yarn的客户端配置来代替该配置。

    morphline.conf

    SOLR_LOCATOR : {
      # Name of solr collection
      collection : event_count_records
      
      # ZooKeeper ensemble 
      #CDH的专有写法,开源版本不支持。
      zkHost : "$ZK_HOST"
      }
    
    morphlines : [
      {
        id : morphline1
        importCommands : ["org.kitesdk.**", "org.apache.solr.**"]
        
        commands : [  
    {
    readLine {
      charset : UTF-8
    }
    }
    {setValues:{_attachment_body : "@{message}"}}
    
    {java:{
    imports:"import java.io.*;import org.kitesdk.morphline.base.Fields;"
    code:"""
    String message=(String)record.getFirstValue(Fields.ATTACHMENT_BODY);
            if(message.contains("'"))
            {
                return true;
            }
            InputStream   inputStream   =   new   ByteArrayInputStream(message.getBytes());
            record.removeAll(Fields.ATTACHMENT_BODY);
            record.put(Fields.ATTACHMENT_BODY, inputStream);
            return child.process(record);
    """
    }}
    
    {
      #Flume传过来的kafka的json数据是用二进制流的形式,需要先读取json
       readJson{}
    }
    
    {
     #读出来的json字段必须转换成filed才能被solr索引到
    extractJsonPaths {
     flatten:true
     paths:{
    account:/account
    accountName:/accountName
    subaccount:/subaccount
    subaccountName:/subaccountName
    eventTime:/timestamp
    eventType:/eventType
    eventTags:"/eventTags[]/name"
    #按UTC时间存timestamp
    eventTimeInMinuteUTC_tdt:/timestamp
    #按China时间存timestamp
    eventTimeInMinuteChina_tdt:/timestamp
    #按UTC时间存timestamp
    eventTimeInHourUTC_tdt:/timestamp
    #_tdt后缀会被动态识别为日期类型的索引字段
    #按不同时间间隔存索引以增加查询性能
    }
     
    }
    }
    
    #转换long型时间为Date格式
    {convertTimestamp {
      field : eventTimeInMinuteChina_tdt
      inputFormats : ["unixTimeInMillis"]
      inputTimezone : UTC
      outputFormat : "yyyy-MM-dd'T'HH:mm:ss.SSS'Z/MINUTE'"
      outputTimezone : Asia/Shanghai
    }}
    
    {convertTimestamp {
      field : eventTimeInMinuteUTC_tdt
      inputFormats : ["unixTimeInMillis"]
      inputTimezone : UTC
      outputFormat : "yyyy-MM-dd'T'HH:mm:ss.SSS'Z/MINUTE'"
      outputTimezone : UTC
    }}
    
    {convertTimestamp {
      field : eventTimeInHourUTC_tdt
      inputFormats : ["unixTimeInMillis"]
      inputTimezone : UTC
      outputFormat : "yyyy-MM-dd'T'HH:mm:ss.SSS'Z/HOUR'"
      outputTimezone : UTC
    }}
    
    #kafka中的json数据传到flume中时会被放入_attachment_body字段,readJson后会变成JsonNode对象,需要toString之后才能保存
    {toString { field : _attachment_body }}
    
    
    #为每一条记录生成一个UUID
    {generateUUID {
      field : id
    }}
    
    sanitizeUnknownSolrFields {
      solrLocator : ${SOLR_LOCATOR}
    }
    
    #对未定义的Solr字段加tws前缀,根据schema.xml中定义的tws_*为text_ws类型,会动态未未定义的字段建索引。  
    
    #将数据导入到solr中                
          {loadSolr {solrLocator : ${SOLR_LOCATOR}}}
        ]
      }
    ]

    log4j.properties:

    log4j.rootLogger=WARN, A1
    
    log4j.logger.org.apache.flume.sink=INFO
    #log4j.logger.org.apache.flume.sink.solr=DEBUG
    log4j.logger.org.apache.solr=INFO
    #log4j.logger.org.apache.solr.hadoop=DEBUG
    log4j.logger.org.kitesdk.morphline=TRACE
    #log4j.logger.org.apache.solr.morphline=DEBUG
    log4j.logger.org.apache.solr.update.processor.LogUpdateProcessor=WARN
    log4j.logger.org.apache.solr.core.SolrCore=WARN
    log4j.logger.org.apache.solr.search.SolrIndexSearcher=ERROR
    
    # A1 is set to be a ConsoleAppender.
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    
    # A1 uses PatternLayout.
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

    map数等于要被批量索引的文件数。

    yarn的客户端配置可以作下修改,设置reduce的个数,每个map占用的内存cpu等(map数不能修改)。

    任务完成提示:

    image

    *批量索引的效率并不一定总是比实时索引高,但优点是不吃solr服务性能——没有调用solr接口,而是直接生成索引文件后移至solr collection目录下。

    *调试morphline.conf bug时先用小点的单个文件,如果morphline写的有错,一个文件的任务失败会导致整个任务失败。

    如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
    如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
    如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【Arli】。

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    libSVM的数据格式
    libSVM 简易使用手册
    python3使用csv模块读写csv文件
    sklearn
    windows下pip升级到8.1.2
    Elasticsearch学习(一)————简单命令
    InnoDB undo log物理结构的初始化
    【java_设计模式】建造者模式
    POI原生导入读取EXCEL
    websocket 进阶!netty框架实现websocket达到高并发
  • 原文地址:https://www.cnblogs.com/arli/p/6248819.html
Copyright © 2011-2022 走看看