RandomAccessFile baixa desduplicação de hash de arquivo e Mapreduce baixa arquivos -------- O modo Bridge executa a limpeza de dados para

A limpeza de dados é justificada? 
Engenheiro off-line ET2 
de conversão de grupo de verificação multidimensional

Método 1: Use RandomAccessFile para baixar o hash do arquivo e remover duplicatas

public class App 
{ 
    public static void main( String[] args ) throws Exception { 
        //Prepara hash 
        HashMap<String, Integer> map = new HashMap<>(); 
        //Lê o arquivo 
        RandomAccessFile raf = new RandomAccessFile("D:\ \bgdata\\bgdata01\\events.csv", "rw"); 
        //Pular a primeira linha 
        raf.readLine(); 
        //Ler uma linha de dados 
        String line=""; 
        //Loop para ler dados 
        while ( (line =raf.readLine())!=null){ 
            //Os dados lidos são separados por vírgulas e a primeira 
            String eventid=line.split(",")[0]; 
            //Determina se o mapa contém id 
            if (mapa. 
            }else { 
                map.put(eventid,mapa.get(eventid)+1);
                //Caso contrário, é a primeira vez que obtemos o valor do id e o configuramos como 1 
                map.put(eventid,1); 
            } 
        } 
        //Fecha o arquivo de stream         
        raf.close(); 
        //Sai e verifica o tamanho do mapa para ver se há duplicatas 
        System.out.println (map.size()+"=============="); 
    } 
}

Desvantagens: Os dados do arquivo usados ​​​​desta vez foram 3 milhões e a leitura foi muito lenta. Demorou cerca de 30 minutos o(╥﹏╥)o

Recomenda-se usar o seguinte método

Método 2 usa Mapreduce para baixar arquivos

2.1Configurar arquivo pom

    <dependency> 
      <groupId>org.apache.hadoop</groupId> 
      <artifactId>hadoop-client</artifactId> 
      <version>2.6.0</version> 
    </dependency> 
    <dependency> 
      <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> 
      <versão>2.6.0</versão>
    </dependency>

2.2 Configurar a classe RcMapper

classe pública RcMapper estende Mapper<LongWritable,Text ,Text, IntWritable> { 
   IntWritable one= new IntWritable(1); 
    @Override 
    mapa vazio protegido (chave LongWritable, valor de texto, contexto de contexto) lança IOException, InterruptedException { 
        String eventid=value.toString().split(",")[0]; 
        context.write(novo Texto(eventid),um); 
    } 
}

2.3 Configurar a classe RcReduce

classe pública RcReduce estende Redutor<Texto, IntWritable,Texto,IntWritable>{ 
    @Override 
    protegido void reduzir(chave de texto, valores Iterable<IntWritable>, contexto de contexto) lança IOException, InterruptedException { 
        int count=0; 
        for (IntWritable it: valores) { 
            contagem+=1; 
        } 
        context.write(chave,new IntWritable(contagem)); 
    } 
}

2.4 Configurar a classe RcCountDriver

public class RcCountDriver { 
    public static void main(String[] args) throws Exception { 
        //Instancia o objeto de trabalho 
        Job job = Job.getInstance(new Configuration()); 
        //Obtém o objeto por meio de reflexão 
        job.setJarByClass(RcCountDriver.class ); 
​//
        Reflexão para obter o objeto RcMapper 
        //Definir o Text.class correspondente 
        job.setMapperClass(RcMapper.class); 
        job.setMapOutputKeyClass(Text.class); 
        job.setMapOutputValueClass(IntWritable.class); 
​//
        Reflexão para obter o objeto RcReduce 
        // Defina o Text.class correspondente 
        job.setReducerClass(RcReduce.class); 
        job.setOutputKeyClass(Text.class); 
        job.setOutputValueClass(IntWritable.class);
//
        Obtenha o caminho do arquivo de destino 
        FileInputFormat.addInputPath(job,new Path("file:///D:\\bgdata\\bgdata01\\events.csv")); // 
        Marque o endereço do arquivo de download 
        FileOutputFormat.setOutputPath (job ,new Path("file:///d:/calres/cal01")); 
​/
        ** 
         *O trabalho é executado através de job.waitForCompletion(true), 
         * true significa que o progresso da execução e outras informações serão saída para o usuário em tempo hábil, 
         * Se for falso, apenas espere o trabalho terminar 
         */ 
        job.waitForCompletion(true); 
    } 
}

Basta clicar para testar! !

Método 3. Use Mapreduce para remover duplicatas

3.1 Configurar a classe CfMapper

public class CfMapper estende Mapper<LongWritable, Text,Text, IntWritable> { 
    @Override 
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { 
        //O valor obtido é separado por espaços 
        String[] infos = value . toString().split("\t"); 
        //Operação se o segundo dado não for um 
        if (!infos[1].equals("1")){ 
            //Obter o primeiro valor, o segundo Remover espaços de valores diferentes de 1 context.write(new Text(infos[0]),new IntWritable(Integer.parseInt(infos 
[ 
            1].trim()))); } 
        } 
    }

3.2 Configurar a classe CfCombiner

classe pública CfCombiner estende Redutor<Texto, IntWritable,Texto,IntWritable> { 
    @Override 
    protected void reduz (chave de texto, valores Iterable<IntWritable>, contexto de contexto) lança IOException, InterruptedException { 
        //配置kv键值对
        context.write(chave ,valores.iterator().next()); 
    } 
}

3.3 Configurar a classe CfCountDriver

public class CfCountDriver { 
    public static void main(String[] args) throws Exception { 
        //Instancia o objeto de trabalho 
        Job job = Job.getInstance(new Configuration()); 
        //Obtém o objeto por meio de reflexão 
        job.setJarByClass(CfCountDriver.class ); 
​//
        Reflexão para obter o objeto CfMapper 
        //Definir o Text.class correspondente 
        job.setMapperClass(CfMapper.class); 
        job.setMapOutputKeyClass(Text.class); 
        job.setMapOutputValueClass(IntWritable.class); 
​//
        Reflexão para obter o objeto CfCombiner 
        // Defina o Text.class correspondente 
// job.setCombinerClass(CfCombiner.class); 
        job.setReducerClass(CfCombiner.class); 
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class); 
//
        Obtém o caminho do arquivo de destino 
        FileInputFormat.addInputPath(job,new Path("file:///d:/calres/cal01/a")); // 
        Marca o endereço do arquivo de download 
        FileOutputFormat .setOutputPath(job,new Path("file:///d:/calres/ca102/")); /** 
        * 
         O trabalho é executado através de job.waitForCompletion(true), 
         * true significa que o progresso da execução e outros as informações serão enviadas a tempo Para o usuário, 
         * se for falso, apenas espere o trabalho terminar 
         */ 
        job.waitForCompletion(true); 
    } 
}

implementação de código kafka de configuração ideal (otimização: modo bridge)

1 Importar arquivo kafka pom

canall extrai dados do banco de dados em tempo real

2Configurar yml

Envie manualmente o monitor de serialização de dados lidos desde o início

server: 
  port: 8999 
spring: 
  application: 
    name: userinterest 
  kafka: 
    bootstrap-servers: 192.168.64.210:9092 #acks=0: Independentemente de sucesso ou falha, envie apenas uma vez. Nenhuma confirmação é necessária 
      #acks=1: ou seja, você só precisa confirmar que o líder recebeu a mensagem 
      #acks=all ou -1: ISR + Líder têm certeza de receber 
    o consumidor: #Se deseja confirmar automaticamente o deslocamento offset 
      enable-auto-commit: false #Earliest: Sem registro de envio, o consumo começa desde o início 
      #latest: Sem registro de envio, o consumo começa a partir da próxima mensagem mais recente 
      auto-offset-reset: mais antigo       #Key método de codificação e decodificação 
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer   #valor método de codificação e decodificação 
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer 
      #Configurar o ouvinte
     
     
     

    
    listener: 
      #Quando o valor de enable.auto.commit for definido como falso, o valor entrará em vigor ; quando for verdadeiro, não terá efeito. 
      # manual_immediate: Você precisa chamar manualmente Acknowledgment.acknowledge() para enviar 
      a confirmação -modo: manual_imediato

3. Configurar modelo de modo bridge

3.1 Classe de interface em modo Bridge

public interface FillHbaseData<T> extends FillData<Put,T> { 
    List<Put> fillData(List<T> lis); 
} 
/

** 
 * Converte formatos de dados de acordo com diferentes dados do usuário e modelos de classe de entidade de entrada Interface 
 * @param < T> 
 */ 
public interface StringToEntity<T> { 
    List<T> change(String line); 
}

3.2 Classe de implementação do modo Bridge

# 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(),"resposta".getBytes(),ea.getAnswer(). getBytes()); 
            coloca.add(colocar); 
        });
        opções de venda de retorno; 
    } 
} 
​# EventFillDataImpl类
public class EventFillDataImpl implements FillHbaseData<Events> { 
    @Override 
    public List<Put> fillData(List<Events> lis) { 
        List<Put> puts = new ArrayList<>(); 
        lis.stream().forEach( 
                event -> { 
                    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()); 
                    coloca.
getBytes()); 
        }); 
        retornar nulo; 
    } 
} 
​# EventAttendeesChangeImpl类

public class EventAttendeesChangeImpl implements StringToEntity<EventAttendees> { 
/

    ** 
     * Os dados entram como eventid sim talvez convidado não 
     * ex:123,112233,34343,234234,45454,112233,23232,234234,3434343,34343 
     * Converta os dados formato Para 123 112233 sim, 123 34343 sim, 123 234234 talvez... 
     * @param line 
     * @return 
     */ 
    @Override 
    public List<EventAttendees> change(String line) { 
        String[] infos = line.split(" ," , -1); 
        List<EventAttendees> eas = new ArrayList<>(); 
        //Primeiro conte todas as pessoas que responderam sim 
        if (infos[1].trim().equals("")&&infos[1]! = nulo){ 
            Arrays.asList(infos[1].dividir(" ")).stream().forEach(
                    sim->{ 
                     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( 
                    talvez->{ 
                        EventAttendees ea = EventAttendees.builder() 
                                .eventid(infos[0]).userid(talvez).answer("talvez") 
                                .build();
                        eas.add(ea); 
                    }); 
        } 
        //Primeiro calcule todas as pessoas que responderam ao convite 
        if (infos[3].trim().equals("")&&infos[3]!=null){ 
            Arrays.asList( infos [3].split(" ")).stream().forEach( 
                    convidado->{ 
                        EventAttendees ea = EventAttendees.builder() 
                                .eventid(infos[0]).userid(convidado).resposta("convidada") 
                                . build(); 
                        eas.add(ea); 
                    }); 
        } 
        //Primeiro calcule todas as pessoas que responderam não 
        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( "não") 
                                .build(); 
                        eas.add(ea); 
                    }); 
        } 
        retornar eas; 
    } 
} 
​# EventsChangeImpl类
public class EventsChangeImpl implements StringToEntity<Events> { 
    @Override 
    public List<Events> change(String line) { 
        String[] infos = line.split(",", -1); 
        List<Eventos> events=new ArrayList<>();

        Eventos evento = Events.builder().eventid(infos[0]).userid(infos[1]).starttime(infos[2]) .city(infos[3]).state(infos[4]). 
                zip (infos[5]).país(infos[6]) 
                .lat(infos[7]).lng(infos[8]).build(); 
        events.add(evento); 
​retornar
        eventos; 
    } 
} 
​# UserFriendsChangeImpl类
/** 
 * 将将123123, 123435 435455 345345 => 123123, 123435 123123,435455 123123, 345345 
 */ 
​classe 
pública 
    @Override 
    public List<UserFriends> change(String linha) { 
        String[] infos = linha.split(",");

        List<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); 
                } 
        ); 
        retornar ufs; 
    } 
}

3.3 Classe abstrata do modo Bridge

/** 
 * #3.3.1 AbstractDataChanage抽象类
 * 桥梁模式中的抽象角色
 */ 
public abstract class AbstractDataChanage<E,T> implements 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
 
    public abstract List<T> change(String line); 
​public
    abstract void fill(ConsumerRecord<String,
/** 
 * #3.3.2 Interface DataChanage 
 * Interface de conversão de dados Os dados kafka são convertidos em formatos de dados comuns 
 * (se houver vários bancos de dados redis hbase oracle, uma interface de preenchimento precisa ser escrita) 
 * @param <T> 
 * 
/
 interface pública 
    List<T> change(String line); 
​}
 
​# 3.3.3 Classe DataChangeFillHbaseDatabase 
classe pública DataChangeFillHbaseDatabase<T> estende 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){ 
        //Leia o ConsumerRecord obtido pelo kafka e converta-o em um string 
        List< Put> puts = fillData.fillData(change(record.value())); 
        //Preenche a coleção no banco de dados hbase correspondente 
    } 
} 
#
 3.3.4 Interface FillData 
public interface FillData<T,E> { 
    List< T> fillData(Lista<E> lst); 
}

3.4 Modo ponte

  

Fábrica abstrata 
a, fábrica abc, 3 produtos, 
fábrica b, fábrica abc, 3 produtos

4. Escreva classes de entidade

@Data 
@AllArgsConstructor 
@NoArgsConstructor 
@Builder 
public class EventAttendees { 
    private String eventid; 
    string privada ID do usuário; 
    resposta de string privada; 
} 
​@Data
 
@AllArgsConstructor 
@NoArgsConstructor 
@Builder 
public class Events { 
    private String eventid; 
    string privada ID do usuário; 
    horário de início da string privada; 
    cidade privada de String; 
    estado de String privado; 
    zip de string privada; 
    país String privado; 
    string privada lat; 
    string privada lng; 
} 
​@Dados

@AllArgsConstructor 
@NoArgsConstructor 
@Builder 
public class UserFriends { 
    private String userid; 
    private String amigo; 
}

5. Gravar classe de configuração

@Configuration 
public class 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("prototype") 
        public Connection getConnection() { 
            Connection connection=null; 
            tente { 
                conexão = ConnectionFactory.createConnection(hbaseConfiguration()); 
            } catch (IOException e) { 
                e.printStackTrace();
       
      
       
            } 
            retornar conexão; 
        } ​@Bean
 
        public Supplier<Conexão> hbaseConSupplier(){ 
            return ()->{ 
                return getConnection(); 
            }; 
        } 
}
       

5.1 Resolver duplicação de dados hbase

hbase subjacente kv k é a chave de linha e a chave de linha é nome de usuário + amigo 
5.2
A quantidade de dados é muito grande? Mais de 30w, dezenas de g, 3000w de dados, cerca de vários g, 
sub-banco de dados, tabela, particionamento vertical 10g 
função hbase função de pré-partição 
partição oracle partição hash intervalo de partição lista partição

5.2 Escrevendo classes de serviço

#5.2.1 
/**
 * Aceita o conjunto de dados List<Put> convertido para preencher o banco de dados 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
classe pública KafkaReader {
@KafkaListener
    (groupId = "cm",tópicos = {"events_raw"})

    public void readEventToHbase(ConsumerRecord<String ,String > record, Acknowledgment ack){ 
        AbstractDataChanage<Put,Events> eventsHandler = new DataChangeFillHbaseDatabase<Events>( 
                new EventFillDataImpl(), 
                new EventsChangeImpl() 
        ); 
        eventsHandler.fill(registro); 
        ack.acknowledge(); 
    } 
    @KafkaListener(groupId = "cm",topics = {"event_attendees_raw"}) 
    public void readEventToHbase1(ConsumerRecord<String ,String > record, Acknowledgment ack){ 
        AbstractDataChanage<Put,
                new EventAttendeesChangeImpl() 
​)
        ; 
        eventsHandler.fill(registro); 
        ack.acknowledge(); 
    } 
    @KafkaListener(groupId = "cm",topics = {"user_friends_raw"}) 
    public void readEventToHbase2(ConsumerRecord<String ,String > record, confirmação de reconhecimento){ 
        AbstractDataChanage<Put, UserFriends> eventsHandler = new DataChangeFillHbaseDatabase<UserFriends>( 
                new UserFriendsFillDataImpl (), 
                novo UserFriendsChangeImpl() 
​)
        ; 
        eventsHandler.fill(registro); 
        ack.acknowledge(); 
    } 
​}

6 Crie cluster de colunas no banco de dados hbase

#Calcular automaticamente a divisão com base no número necessário de regiões e algoritmo de divisão 
criar 'userfriends','base',{ NUMREGIONS   => 3, SPLITALGO  =>'HexStringSplit' } 
​============ ==
============================================== == ====== NUMREGIONS descrição: 
o tamanho padrão do HFile do 
hbase 
Os dados de origem
são Hive: Número recomendado de partições ≈ tamanho do HDFS/10G * 10 * 1.2 
​HexStringSplit
, UniformSplit, DecimalStringSplit Descrição: 
​UniformSplit
(pequena ocupação de espaço, prefixo de chave de linha completamente aleatório •••••••): um agregado que divide uniformemente o espaço de chaves possíveis. Isso é recomendado quando as chaves são bytes aleatórios aproximadamente consistentes (como hashes). As linhas são valores de bytes brutos no intervalo 00 => FF, preenchidos à direita com 0s para manter a mesma ordem memcmp(). Este é um algoritmo natural para um ambiente byte[] e economiza espaço, mas não é necessariamente o mais simples em termos de legibilidade.

HexStringSplit (ocupa muito espaço, rowkey é uma string hexadecimal como prefixo •••••••): HexStringSplit é um RegionSplitter.SplitAlgorithm típico para selecionar o limite da região. O formato dos limites da região HexStringSplit é uma representação ASCII de uma soma de verificação MD5 ou qualquer outro valor hexadecimal distribuído uniformemente. Row é um valor longo codificado em hexadecimal no intervalo "00000000" => "FFFFFFFF", preenchido à esquerda com 0s para que permaneça lexicograficamente na mesma ordem do binário. Como esse algoritmo de divisão usa strings hexadecimais como chaves, é fácil de ler e escrever no shell, mas ocupa mais espaço e pode não ser intuitivo. 
DecimalStringSplit: rowkey é uma string decimal como um prefixo 
===================================== === ============================== 
​criar
'eventAttendees','base' 
​cat
events.csv.COMPLETED | head -2 
​cd
/opt/data/attendees 
cat event_attendees_raw |head -2 
​criar
'eventos' 'base'

6.1 comando de inicialização hbase

#hbaseStart
 start-hbase.sh 
ou inicie o script! ! ! ! O script é o seguinte #Endereço do navegador http://192.168.64.210: 60010 /master-status

Acho que você gosta

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