RandomAccessFile descarga la deduplicación de hash de archivos y Mapreduce descarga archivos--------El modo puente realiza la limpieza de datos para

¿Está justificada la limpieza de datos? 
Ingeniero fuera de línea ET2 
de conversión de grupo de grupo de verificación multidimensional

Método 1: utilice RandomAccessFile para descargar el hash del archivo y eliminar duplicados

aplicación de clase pública 
{ 
    public static void main( String[] args ) throws Exception { 
        //Preparar hash 
        HashMap<String, Integer> map = new HashMap<>(); 
        //Leer archivo 
        RandomAccessFile raf = new RandomAccessFile("D:\ \bgdata\\bgdata01\\events.csv", "rw"); 
        //Omitir la primera línea 
        raf.readLine(); 
        //Leer una línea de datos 
        String line=""; 
        //Bucle para leer datos 
        while ( (line =raf.readLine())!=null){ 
            //Los datos leídos están separados por comas y la primera 
            cadena eventid=line.split(",")[0]; 
            //Determina si el mapa contiene id 
            si (mapa .containsKey(eventid)){ 
                map.put(eventid,map.obtener(eventid)+1);
                // De lo contrario, es la primera vez que obtenemos el valor de id y lo configuramos en 1 
            }else {
                map.put(eventid,1); 
            } 
        } 
        //Cerrar el archivo de flujo         
        raf.close(); 
        //Salir y verificar el tamaño del mapa para ver si hay duplicados 
        System.out.println(map.size()+" ===== ========="); 
    } 
}

Desventajas: los datos del archivo utilizados esta vez fueron 3 millones y la lectura fue muy lenta, tomó alrededor de 30 minutos o (╥﹏╥) o

Se recomienda utilizar el siguiente método.

El método 2 usa Mapreduce para descargar archivos

2.1Configurar el archivo pom

    <dependencia> 
      <groupId>org.apache.hadoop</groupId> 
      <artifactId>hadoop-client</artifactId> 
      <versión>2.6.0</versión> 
    </dependencia> 
    <dependencia> 
      <groupId>org.apache.hadoop </groupId> 
      <artifactId>hadoop-mapreduce-client-core</artifactId> 
      <version>2.6.0</version> 
    </dependency> 
    <dependency> 
      <groupId>org.apache.hadoop</groupId> 
      <artifactId> hadoop-hdfs</artifactId> 
      <version>2.6.0</version> 
    </dependency> 
    <dependency> 
      <groupId>org.apache.hadoop</groupId> 
      <artifactId>hadoop-common</artifactId> 
      <versión>2.6.0</versión>
    </dependencia>

2.2 Configurar la clase RcMapper

clase pública RcMapper extiende Mapper<LongWritable,Text,Text, IntWritable> { 
   IntWritable one= new IntWritable(1); 
    @Override 
    mapa vacío protegido (clave LongWritable, valor de texto, contexto de contexto) arroja IOException, InterruptedException { 
        String eventid=value.toString().split(",")[0]; 
        contexto.write(nuevo texto(eventid),uno); 
    } 
}

2.3 Configurar la clase RcReduce

la clase pública RcReduce extiende Reductor<Texto, IntWritable,Text,IntWritable>{ 
    @Override 
    protected void reduce(Clave de texto, valores Iterable<IntWritable>, contexto de contexto) lanza IOException, InterruptedException { 
        int count=0; 
        for (IntWritable it: valores) { 
            recuento+=1; 
        } 
        contexto.write(clave,nuevo IntWritable(recuento)); 
    } 
}

2.4 Configurar la clase RcCountDriver

public class RcCountDriver { 
    public static void main(String[] args) throws Exception { 
        //Crear una instancia del objeto de trabajo 
        Job job = Job.getInstance(new Configuration()); 
        //Obtener el objeto a través de la reflexión 
        job.setJarByClass(RcCountDriver.class ); 
​//
        Reflexión para obtener el objeto RcMapper 
        //Establece el Text.class correspondiente 
        job.setMapperClass(RcMapper.class); 
        job.setMapOutputKeyClass(Text.class); 
        job.setMapOutputValueClass(IntWritable.class); 
​//
        Reflexión para obtener el objeto RcReduce 
        // Establezca el Text.class correspondiente 
        job.setReducerClass(RcReduce.class); 
        job.setOutputKeyClass(Text.class); 
        job.setOutputValueClass(IntWritable.class);
​//
        Obtener el archivo de ruta de destino 
        FileInputFormat.addInputPath(job,new Path("file:///D:\\bgdata\\bgdata01\\events.csv")); // 
        Marcar la dirección del archivo de descarga 
        FileOutputFormat.setOutputPath (trabajo, nueva ruta("file:///d:/calres/cal01")); 
​/
        ** 
         *El trabajo se ejecuta a través de job.waitForCompletion(true), 
         * verdadero significa que el progreso de la ejecución y otra información serán enviar al usuario de manera oportuna, 
         * Si es falso, simplemente espere a que finalice el trabajo 
         */ 
        job.waitForCompletion(true); 
    } 
}

¡Simplemente haga clic para probar! !

Método 3. Utilice Mapreduce para eliminar duplicados

3.1 Configurar la clase CfMapper

public class CfMapper extends Mapper<LongWritable, Text,Text, IntWritable> { 
    @Override 
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { 
        //El valor obtenido está separado por espacios 
        String[] infos = value . toString().split("\t"); 
        //Operación si el segundo dato no es uno 
        if (!infos[1].equals("1")){ 
            //Obtener el primer valor, el segundo Quitar espacios a partir de valores distintos de 1 
            context.write(new Text(infos[0]),new IntWritable(Integer.parseInt(infos[1].trim()))); 
        } 
    } 
}

3.2 Configurar la clase CfCombiner

la clase pública CfCombiner extiende Reducer<Text, IntWritable,Text,IntWritable> { 
    @Override 
    protected void reduce(Clave de texto, valores Iterable<IntWritable>, contexto de contexto) throws IOException, InterruptedException { 
        //配置kv键值对
        context.write(key ,valores.iterador().siguiente()); 
    } 
}

3.3 Configurar la clase CfCountDriver

public class CfCountDriver { 
    public static void main(String[] args) throws Exception { 
        //Crear una instancia del objeto de trabajo 
        Job job = Job.getInstance(new Configuration()); 
        //Obtener el objeto a través de la reflexión 
        job.setJarByClass(CfCountDriver.class ); 
​//
        Reflexión para obtener el objeto CfMapper 
        //Establece el Text.class correspondiente 
        job.setMapperClass(CfMapper.class); 
        job.setMapOutputKeyClass(Text.class); 
        job.setMapOutputValueClass(IntWritable.class); 
​//
        Reflexión para obtener el objeto CfCombiner 
        // Establezca el Text.class correspondiente 
// job.setCombinerClass(CfCombiner.class); 
        job.setReducerClass(CfCombiner.class); 
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class); 
//
        Obtener el archivo de ruta de destino 
        FileInputFormat.addInputPath(job,new Path("file:///d:/calres/cal01/a")); // 
        Marcar la dirección del archivo de descarga 
        FileOutputFormat .setOutputPath(job,new Path("file:///d:/calres/ca102/")); 
        /** 
         *El trabajo se ejecuta a través de job.waitForCompletion(true), 
         * true significa que el progreso de la ejecución y otros la información se enviará a tiempo Para el usuario, 
         * si es falso, simplemente espere a que finalice el trabajo 
         */ 
        job.waitForCompletion(true); 
    } 
}

Configuración ideal para la implementación del código Kafka (optimización: modo puente)

1 Importar archivo kafka pom

canal extrae datos de la base de datos en tiempo real

2Configurar yml

Envíe manualmente el monitor de serialización de datos leídos desde el principio

servidor: 
  puerto: 8999 
primavera: 
  aplicación: 
    nombre: interés del usuario 
  kafka: 
    servidores bootstrap: 192.168.64.210:9092 #acks=0: Independientemente del éxito o el fracaso, envíe solo una vez. No se requiere confirmación 
      #acks=1: es decir, solo necesita confirmar que el líder ha recibido el mensaje 
      #acks=all o -1: ISR + Leader seguramente recibirá 
    al consumidor: #Si se debe confirmar automáticamente la compensación 
      enable-auto-commit: false #Earliest: Sin registro de envío, el consumo comienza desde el principio 
      #latest: Sin registro de envío, el consumo comienza desde el siguiente mensaje más reciente 
      auto-offset-reset: más antiguo       #Método de codificación y decodificación 
      de claves deserializador de claves: org.apache.kafka.common.serialization.StringDeserializer   #método de codificación y decodificación de valores 
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer 
      #Configurar el oyente
     
     
     

    
    oyente: 
      #Cuando el valor de enable.auto.commit se establece en falso, el valor tendrá efecto ; cuando sea verdadero, no tendrá efecto. 
      # manual_immediate: debe llamar manualmente a Acknowledgment.acknowledge() para enviar 
      un reconocimiento -modo: manual_inmediato

3. Configurar la plantilla del modo puente

3.1 Clase de interfaz en modo puente

interfaz pública FillHbaseData<T> extiende FillData<Put,T> { 
    List<Put> fillData(List<T> lis); 
} 
/

** 
 * Convertir formatos de datos según diferentes datos de usuario y modelos de clase de entidad entrantes Interfaz 
 * @param < T> 
 */ 
interfaz pública StringToEntity<T> { 
    Lista<T> cambio(línea de cadena); 
}

3.2 Clase de implementación del modo puente

# EventAttendessFillDataImpl类
public class EventAttendessFillDataImpl implements FillHbaseData<EventAttendees> {
    @Override
    public List<Put> fillData(List<EventAttendees> lst) {
        List<Put> puts = new ArrayList<>(); 
        lst.stream().forEach(ea->{
            Put put = new Put((ea.getEventid() + ea.getUserid() + ea.getAnswer()).getBytes());
            put.addColumn("base" .getBytes(),"eventid".getBytes(),ea.getAnswer().getBytes());
            put.addColumn("base".getBytes(),"userid".getBytes(),ea.getAnswer(). getBytes());
            put.addColumn("base".getBytes(),"answer".getBytes(),ea.getAnswer(). getBytes()); 
            pone.add(poner); 
        });
        devolución pone; 
    } 
} 
​# EventFillDataImpl类
public class EventFillDataImpl implements FillHbaseData<Events> { 
    @Override 
    public List<Put> fillData(List<Events> lis) { 
        List<Put> puts = new ArrayList<>(); 
        lis.stream().forEach( 
                evento -> { 
                    Put put = new Put(event.getEventid().getBytes()); 
                    put.addColumn("base".getBytes(),"userid".getBytes(),event .getUserid().getBytes()); 
                    put.addColumn("base".getBytes(),"starttime".getBytes(),event.getStarttime().getBytes()); 
                    put.addColumn("base".

                    put.addColumn("base".getBytes(),"zip".getBytes(),event.getZip().getBytes()); 
                    put.addColumn("base".getBytes(),"estado".getBytes(),event.getState().getBytes()); 
                    put.addColumn("base".getBytes(),"país".getBytes(),event.getCountry().getBytes()); 
                    put.addColumn("base".getBytes(),"lat".getBytes(),event.getLat().getBytes()); 
                    put.addColumn("base".getBytes(),"lng".getBytes(),event.getLng().getBytes()); 
                    pone.
getBytes()); 
        }); 
        devolver nulo; 
    } 
} 
​# EventAttendeesChangeImpl类

public class EventAttendeesChangeImpl implements StringToEntity<EventAttendees> { 
​​/

    ** 
     * Los datos ingresan como eventid si tal vez invitado no 
     * ex:123,112233,34343,234234,45454,112233,23232,234234,3434343,34343 
     * Convertir los datos formato Para 123 112233 sí, 123 34343 sí, 123 234234 tal vez... 
     * @param line 
     * @return 
     */ 
    @Override 
    public List<EventAttendees> change(String line) { 
        String[] infos = line.split(" ," , -1); 
        List<EventAttendees> eas = new ArrayList<>(); 
        //Primero cuenta todas las personas que respondieron que sí 
        if (infos[1].trim().equals("")&&infos[1]! = nulo){ 
            Arrays.asList(información[1].dividir(" ")).stream().forEach(
                    yes->{ 
                     EventAttendees ea = EventAttendees.builder() 
                             .eventid(infos[0]).userid(yes).answer("yes") 
                             .build(); 
                        eas.add(ea); 
                    }); 
        } 
        //先计算所有回答maybe的人
        if (infos[2].trim().equals("")&&infos[2]!=null){ 
            Arrays.asList(infos[2].split(" ")) .stream().forEach( 
                    tal vez->{ 
                        EventAttendees ea = EventAttendees.builder() 
                                .eventid(infos[0]).userid(tal vez).answer("tal vez") 
                                .build();
                        eas.add(ea); 
                    }); 
        } 
        //Primero calcula todas las personas que respondieron invitadas 
        if (infos[3].trim().equals("")&&infos[3]!=null){ 
            Arrays.asList( infos [3].split(" ")).stream().forEach( 
                    invitado->{ 
                        EventAttendees ea = EventAttendees.builder() 
                                .eventid(infos[0]).userid(invitado).answer("invitado") 
                                . build(); 
                        eas.add(ea); 
                    }); 
        } 
        //Primero calcula todas las personas que respondieron que no 
        if (infos[4].trim().equals("")&&infos[4]!=null) {
            Arrays.asList(infos[4].split(" ")).stream().forEach( 
                    no->{ 
                        EventAttendees ea = EventAttendees.builder() 
                                .eventid(infos[0]).userid(no).answer( "no") 
                                .build(); 
                        eas.add(ea); 
                    }); 
        } 
        devolver fácil; 
    } 
} 
​# EventsChangeImpl类
public class EventsChangeImpl implements StringToEntity<Events> { 
    @Override 
    public List<Events> cambio(String line) { 
        String[] infos = line.split(",", -1); 
        Lista<Eventos> eventos=new ArrayList<>();

        Eventos evento = Events.builder().eventid(infos[0]).userid(infos[1]).starttime(infos[2]) .city(infos[3]).state(infos[4]). 
                zip (información[5]).country(información[6]) 
                .lat(información[7]).lng(información[8]).build(); 
        eventos.add(evento); 
​devolver
        eventos; 
    } 
} 
​# UserFriendsChangeImpl类
/** 
 * 将将123123, 123435 435455 345345 => 123123, 123435 123123,435455 123123, 345345 * 
 / 
​public
class UserFriendsChangeImpl implementa StringToEntity<User Amigos> { 
    @Override 
    lista pública<UserFriends> cambio(Cadena línea) { 
        String[] infos = line.split(",");

        Lista<UserFriends> ufs = new ArrayList<>(); 
        Arrays.asList((infos[1]).split(" ")).stream().forEach( 
                fid->{ 
                    UserFriends uf = UserFriends.builder().userid(infos[0]).friendid(fid). construir(); 
                    ufs.add(uf); 
                } 
        ); 
        devolver ufs; 
    } 
}

3.3 Clase abstracta en modo puente

/** 
 * #3.3.1 AbstractDataChanage抽象类
 * 桥梁模式中的抽象角色
 */ 
clase abstracta pública AbstractDataChanage<E,T> implementa DataChanage<T> { 
​protected
    FillData<E,T> fillData; 
    protected StringToEntity<T> stringToEntity; 
public

    AbstractDataChanage(FillData<E, T> fillData, StringToEntity<T> stringToEntity) { 
        this.fillData = fillData; 
        this.stringToEntity = stringToEntity; 
    } 
    ​@Override
 
    lista abstracta pública<T> cambio(línea de cadena); 
    ​relleno vacío abstracto 
público
/** 
 * #3.3.2 Interfaz DataChanage 
 * Interfaz de conversión de datos Los datos Kafka se convierten a formatos de datos comunes 
 * (si hay varias bases de datos de Redis Hbase Oracle, se debe escribir una interfaz de llenado) 
 * @param <T> 
 * 
/
 interfaz pública 
    List<T> cambio(String line); 
​}
 
​# 3.3.3 Clase DataChangeFillHbaseDatabase clase 
pública DataChangeFillHbaseDatabase<T> extiende AbstractDataChanage<Put,T> { 
​public
    DataChangeFillHbaseDatabase( 
            FillData<Put,T> fillData, 
            StringToEntity<T > stringToEntity) 
    { 
        super(fillData,stringToEntity); 
    } 
    @Override



    public List<T> change(String line){ 
​return
        stringToEntity.change(line); 
    } 
    ​@Override
 
    public void fill(ConsumerRecord<String,String> record){ 
        //Leer el ConsumerRecord obtenido por kafka y convertirlo en un string 
        List< Put> puts = fillData.fillData(change(record.value())); 
        //Completa la colección en la base de datos hbase correspondiente 
    } 
} 
#
 3.3.4 Interfaz FillData 
public interface FillData<T,E> { 
    List< T> fillData(Lista<E> lst); 
}

3.4 Modo puente

  

Resumen fábrica 
a, fábrica abc, 3 productos, 
fábrica b, fábrica abc, 3 productos

4. Escribe clases de entidad.

@Data 
@AllArgsConstructor 
@NoArgsConstructor 
@Builder 
public class EventAttendees { 
    cadena privada eventid; 
    ID de usuario de cadena privada; 
    respuesta de cadena privada; 
} 
​@Data
 
@AllArgsConstructor 
@NoArgsConstructor 
@Builder 
public class Eventos { 
    cadena privada eventid; 
    ID de usuario de cadena privada; 
    hora de inicio de cadena privada; 
    ciudad privada de cuerdas; 
    estado de cadena privada; 
    zip de cadena privada; 
    país de cadena privada; 
    cadena privada lat; 
    longitud de cadena privada; 
} 
​@Datos

@AllArgsConstructor 
@NoArgsConstructor 
@Builder 
public class UserFriends { 
    cadena privada ID de usuario; 
    ID de amigo de cadena privada; 
}

5.Escribir clase de configuración

@Configuration 
clase pública HbaseConfig { ​@Bean
 
        public org.apache.hadoop.conf.Configuration hbaseConfiguration(){ 
            org.apache.hadoop.conf.Configuration cfg= HBaseConfiguration.create(); 
            cfg.set(HConstants.ZOOKEEPER_QUORUM,"192.168.64.210:2181"); 
            return cfg; 
        ​}
   ​@Bean
 @Scope("prototipo") 
        Conexión pública getConnection() { 
            Conexión conexión=null; 
            intente { 
                conexión = ConnectionFactory.createConnection(hbaseConfiguration()); 
            } captura (IOException e) { 
                e.printStackTrace();
       
      
       
            } 
            conexión de retorno; 
        } ​@Bean
 
        proveedor público<Conexión> hbaseConSupplier(){ 
            return ()->{ 
                return getConnection(); 
            }; 
        } 
}
       

5.1 Resolver la duplicación de datos hbase

hbase subyacente kv k es la clave de fila y la clave de fila es nombre de usuario + amigo 
5.2
¿La cantidad de datos es demasiado grande? Más de 30w, docenas de g, 3000w de datos, aproximadamente varios g, 
subbase de datos, tabla, partición vertical 10g 
función hbase función de prepartición partición 
oracle rango de partición hash partición lista de particiones

5.2 Clases de servicio de redacción

#5.2.1 
/**
 * Acepte el conjunto de datos List<Put> convertido para completar la base de datos Hbase
 */
​@Component

public class HbaseWriter {
    @Resource
    private Connection hbaseConnection;
​public
    void write(List<Put> puts,String tableName ){
        try {
            Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
            table.put(puts);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
​# 5.2.2 
@Component
clase pública KafkaReader {
@KafkaListener
    (groupId = "cm", temas = {"events_raw"})

    public void readEventToHbase(ConsumerRecord<String ,String > record, Acknowledgement ack){ 
        AbstractDataChanage<Put,Events> eventsHandler = new DataChangeFillHbaseDatabase<Events>( 
                new EventFillDataImpl(), 
                new EventsChangeImpl() 
        ); 
        eventsHandler.fill(registro); 
        reconocimiento.reconocimiento(); 
    } 
    @KafkaListener(groupId = "cm",topics = {"event_attendees_raw"}) 
    public void readEventToHbase1(ConsumerRecord<String ,String > record, Acknowledgement ack){ 
        AbstractDataChanage<Put,
                nuevo EventAttendeesChangeImpl() 
​)
        ; 
        eventsHandler.fill(registro); 
        reconocimiento.reconocimiento(); 
    } 
    @KafkaListener(groupId = "cm",topics = {"user_friends_raw"}) 
    public void readEventToHbase2(ConsumerRecord<String ,String > record, Acknowledgement ack){ 
        AbstractDataChanage<Put, UserFriends> eventsHandler = new DataChangeFillHbaseDatabase<UserFriends>( 
                new UserFriendsFillDataImpl (), 
                nuevo UserFriendsChangeImpl() 
​)
        ; 
        eventsHandler.fill(registro); 
        reconocimiento.reconocimiento(); 
    } 
​}

6 Crear grupo de columnas en la base de datos hbase

# Calcule automáticamente la división en función del número requerido de regiones y el algoritmo de división 
cree 'userfriends','base',{ NUMREGIONS   => 3, SPLITALGO  =>'HexStringSplit' } 
​============ ==
================================================== == ====== Descripción de NUMREGIONS : 
el tamaño predeterminado del archivo 
Hbase de hbase 
Los datos de origen
son Hive: número recomendado de particiones ≈ tamaño HDFS/10G * 10 * 1.2 
​HexStringSplit
, UniformSplit, DecimalStringSplit Descripción: 
​UniformSplit
(ocupación de espacio pequeño, prefijo de clave de fila completamente aleatorio •••••••): un agregado que divide uniformemente el espacio de posibles claves. Esto se recomienda cuando las claves son bytes aleatorios aproximadamente consistentes (como hashes). Las filas son valores de bytes sin formato en el rango 00 => FF, rellenados a la derecha con 0 para mantener el mismo orden de memcmp(). Este es un algoritmo natural para un entorno de bytes[] y ahorra espacio, pero no es necesariamente el más simple en términos de legibilidad.

HexStringSplit (ocupa mucho espacio, la clave de fila es una cadena hexadecimal como prefijo •••••••): HexStringSplit es un RegionSplitter.SplitAlgorithm típico para seleccionar el límite de la región. El formato de los límites de la región HexStringSplit es una representación ASCII de una suma de comprobación MD5 o cualquier otro valor hexadecimal distribuido uniformemente. La fila es un valor largo codificado en hexadecimal en el rango "00000000" => "FFFFFFFF", rellenado a la izquierda con 0 para que permanezca lexicográficamente en el mismo orden que el binario. Debido a que este algoritmo de división utiliza cadenas hexadecimales como claves, es fácil de leer y escribir en el shell, pero ocupa más espacio y puede no ser intuitivo. 
DecimalStringSplit: filakey es una cadena decimal como prefijo 
======================================= === ============================== 
​crear
'eventAttendees','base' 
​cat
events.csv.COMPLETED | head -2 
​cd
/opt/data/attendes 
cat event_attendees_raw |head -2 
​crea
'eventos' 'base'

6.1 comando de inicio de hbase

#hbaseStart
 start-hbase.sh 
o inicia el script. ! ! ! El script es el siguiente #Dirección del navegador http://192.168.64.210: 60010 /master-status

Supongo que te gusta

Origin blog.csdn.net/just_learing/article/details/126273880
Recomendado
Clasificación