Como adicionar um novo tipo de dados ao banco de dados gráfico NebulaGraph, tomando Binary como exemplo

As estruturas de dados que vêm com o kernel NebulaGraph são na verdade muito ricas, como Lista, Conjunto, Mapa, Duração, DataSet, etc. No entanto, quando normalmente construímos tabelas e escrevemos dados, as estruturas de dados que podem ser usadas são relativamente limitadas . Estruturas complexas atualmente suportam apenas os seguintes tipos:

enum PropertyType {
    UNKNOWN = 0,
    ...             // 基础类型

    TIMESTAMP = 21,
    DURATION = 23,
    DATE = 24,
    DATETIME = 25,
    TIME = 26,

    GEOGRAPHY = 31,
} (cpp.enum_strict)

Então, às vezes, devido a necessidades de negócios, precisamos ser capazes de armazenar alguns tipos de dados personalizados, como aqueles frequentemente usados ​​em aprendizado de máquinaIncorporação tipo de dados, muitas vezes há necessidade de armazenar diretamente dados bináriosBinários em projetos, o que exige que os desenvolvedores adicionem um tipo de dados para atender à necessidade. próprias necessidades de desenvolvimento de negócios.

Este artigo ensinará passo a passo como adicionar um tipo de dados no NebulaGraph até que você possa criar uma tabela e inserir os dados e consultas correspondentes.

Abaixo explicaremos todo o processo com as etapas de adição de um tipo binário simples Binary.

1. Projeto de comando

Antes de implementar o novo tipo Binário, primeiro pensamos em que tipo de comando usar esse tipo. Podemos nos referir ao uso de tipos de dados existentes no NebulaGraph.

1.1 comando de criação de esquema

// 创建点表
create tag player(name string, image binary)
// 创建边表
create edge team(name string, logo binary)

Quando projetamos o novo esquema acima, usamos a palavra-chave binary para indicar a configuração do campo de atributo de tipo binário.

1.2 Inserir dados

Um problema aqui é que os comandos só podem ser transmitidos em forma de string, portanto, se inserirmos dados binários por meio de comandos, precisaremos transcodificar. Aqui tomamos a codificação Base64 como exemplo.

insert vertex player values "p1":("jimmy", binary("0s=W9d...."))

Também usamos uma palavra-chave binary no comando de inserção para indicar que a string de dados binários está sendo inserida em vez de uma string comum.

1.3 Consultar dados

Na verdade, a partir do design normal ou do código NebulaGraph existente, a instrução de consulta não precisa ser alterada. Basta ler o campo Binary como se fosse ler outros dados. , mas aqui precisamos considerar uma questão, o que devemos fazer se o cliente não estiver adaptado? Para clientes como nebula-console, nebula-java e nebula-cpp, estamos temporariamente impossibilitados de nos adaptar aos novos tipos um por um, portanto, para usar o nebula-console para ler dados normalmente durante o teste, precisamos fornecer conversão Função para converter o tipo Binary recém-adicionado em um formato de dados que possa ser lido pelo cliente existente.

fetch prop on player "p1" yield base64(player.image) as img_base64

Aqui definimos uma função de conversão base64() para gerar os dados binários armazenados no formato Base64. (De volta ao ponto de partida depois de dar voltas e mais voltas (:≡)

Depois de definir o comando, vamos ver como implementar este conteúdo. Primeiro precisamos implementar esta Binary estrutura de dados.

2. Defina a estrutura de dados

No código C++ do lado do servidor, podemos usar uma matriz Bytes para representar a estrutura de dados binária

struct Binary {
    std::vector<std::byte> values;

    Binary() = default;
    Binary(const Binary &) = default;
    Binary(Binary &&) noexcept = default;
    explicit Binary(std::vector<std::byte> &&vals);
    explicit Binary(const std::vector<std::byte> &l);

    // 用于直接从命令行的字符串中解析出二进制
    explicit Binary(const std::string &str);
    
    ... // 其他接口
};

Depois que uma estrutura de dados simples for definida, precisamos adicionar essa estrutura à união de Value

Valor Esta estrutura de dados é definida em Value.cpp. É uma representação de classe base de todas as estruturas de dados em nebulosa. Se cada nova estrutura de dados quiser ser misturada com outras estruturas de dados anteriores, você precisará enfrentar cada uma em Value.cpp. Adaptar a interface.

Existem muitas definições de interface nesta estrutura de dados de valor, como construção de atribuição, sobrecarga de símbolos, toString, toJson, hash e outras interfaces, todas as quais precisam ser adaptadas.

Felizmente, isso não é difícil, basta referir-se a outros tipos de implementações. A única coisa a observar é ter cuidado!

2.1 Defina a estrutura de dados da economia

Como nossa estrutura de dados também precisa de transmissão de rede, também precisamos definir o tipo de estrutura no arquivo thrift e implementar recursos de serialização.

// 新增的数据类型
struct Binary {
    1: list<byte> values;
} (cpp.type = "nebula::Binary")

// 在Value union中增加Binary类型
union Value {
    1: NullType                                 nVal;
    2: bool                                     bVal;
    3: i64                                      iVal;
    4: double                                   fVal;
    5: binary                                   sVal;
    6: Date                                     dVal;
    7: Time                                     tVal;
    8: DateTime                                 dtVal;
    9: Vertex (cpp.type = "nebula::Vertex")     vVal (cpp.ref_type = "unique");
    10: Edge (cpp.type = "nebula::Edge")        eVal (cpp.ref_type = "unique");
    11: Path (cpp.type = "nebula::Path")        pVal (cpp.ref_type = "unique");
    12: NList (cpp.type = "nebula::List")       lVal (cpp.ref_type = "unique");
    13: NMap (cpp.type = "nebula::Map")         mVal (cpp.ref_type = "unique");
    14: NSet (cpp.type = "nebula::Set")         uVal (cpp.ref_type = "unique");
    15: DataSet (cpp.type = "nebula::DataSet")  gVal (cpp.ref_type = "unique");
    16: Geography (cpp.type = "nebula::Geography")   ggVal (cpp.ref_type = "unique");
    17: Duration (cpp.type = "nebula::Duration")     duVal (cpp.ref_type = "unique");
    18: Binary (cpp.type = "nebula::Binary") btVal (cpp.ref_type = "unique");
} (cpp.type = "nebula::Value")

Além disso, também precisamos adicionar um tipo à enumeração no arquivo common.thrift. PropertyTypeBINARY

enum PropertyType {
    UNKNOWN = 0,
    ...             // 基础类型

    TIMESTAMP = 21,
    DURATION = 23,
    DATE = 24,
    DATETIME = 25,
    TIME = 26,

    GEOGRAPHY = 31,
    BINARY = 32,
} (cpp.enum_strict)

2.2 Implementar a serialização do formato rpc econômico do Binary

O código aqui não será mostrado. Você também pode consultar outros tipos de implementações. O mais próximo pode se referir à implementação de src/common/datatypes/ListOps-inl.h

3. Implementação de linha de comando

Depois que a estrutura de dados for definida, podemos iniciar a implementação da linha de comando. Primeiro abrasrc/parser/scanner.lex. Precisamos adicionar uma palavra-chaveBinary:

"BINARY"                    { return TokenType::KW_BINARY; }

Em seguida, abra o arquivo src/parser/parser.yy e declare as palavras-chave:

$token KW_BINARY

Para minimizar o impacto da linha de comando, adicionamos a palavra-chave Binary ao conjunto de palavras-chave não reservadas:

unreserved_keyword
    ...
    | KW_BINARY             { $$ = new std::string("binary"); }

Em seguida, precisamos adicionar a palavra-chaveBinary à árvore de léxico do comando de criação de tabela:

type_spec
    ...
    | KW_BINARY {
        $$ = new meta::cpp2::ColumnTypeDef();
        $$->type_ref() = nebula::cpp2::PropertyType::BINARY;
    }

Finalmente implementamos o comando insert:

constant_expression
    ...
    | KW_BINARY L_PAREN STRING R_PAREN {
        $$ = ConstantExpression::make(qctx->objPool(), Value(Binary(*$3)));
        delete $3;
    }

Desta forma, simplesmente implementamos os comandos para criar o esquema binário e inserir dados binários no design de comando acima.

4. Adaptação de leitura e escrita de serviço armazenado

Acima concluímos a definição da estrutura de dados, serialização do rpc e adaptação da linha de comando.Após a criação de uma nova estrutura de dados através do comando, o serviço grapd recebe a solicitação e a transmite para o servidor armazenado. No entanto, os dados reais armazenados no servidor armazenado são uma string codificada. Precisamos escrever uma lógica de código de codificação e decodificação para esta nova estrutura de dados.

4.1 Adaptação de escrita RowWriterV2

No arquivo de código src/codec/RowWriterV2.cpp, existem as seguintes funções que precisam ser adaptadas.

RowWriterV2::RowWriterV2(RowReader& reader) // 构造函数中适配新增的类似

WriteResult RowWriterV2::write(ssize_t index, const Binary& v) // 新增一个Binary的编码写入函数

Aqui eu escrevo diretamente o array Bytes em String

WriteResult RowWriterV2::write(ssize_t index, const Binary& v) noexcept {
  return write(index, folly::StringPiece(reinterpret_cast<const char*>(v.values.data()), v.values.size()));
}

4.2 Adaptação de leitura RowReaderV2

No arquivo de código src/codec/RowReaderV2.cpp, também existem as seguintes funções que precisam ser adaptadas

Value RowReaderV2::getValueByIndex(const int64_t index) const {
    ...
    case PropertyType::VID: {
      // This is to be compatible with V1, so we treat it as
      // 8-byte long string
      return std::string(&data_[offset], sizeof(int64_t));
    }
    case PropertyType::FLOAT: {
      float val;
      memcpy(reinterpret_cast<void*>(&val), &data_[offset], sizeof(float));
      return val;
    }
    case PropertyType::DOUBLE: {
      double val;
      memcpy(reinterpret_cast<void*>(&val), &data_[offset], sizeof(double));
      return val;
    }
    ...
        
    // code here
    case PropertyType::BINARY: {
        ...
    }
}

O que é preciso ressaltar é: a leitura e a escrita devem ser mapeadas, e o modo de escrever é o modo de ler.

Neste ponto, o processo de adição de um novo tipo de dados no NebulaGraph está concluído.

Veja o efeito


Obrigado por ler (///▽///)

Interessado no banco de dados gráfico NebulaGraph? Bem-vindo ao GitHub ✨ Veja o código fonte: https://github.com/vesoft-inc/nebula; Quer trocar experiências com outros entusiastas da tecnologia gráfica? Faça amizade com NebulaGraph Miss Nebula e participe do grupo de comunicação; 

Tang Xiaoou, fundador da SenseTime, faleceu aos 55 anos Em 2023, o PHP estagnou O Wi-Fi 7 estará totalmente disponível no início de 2024 Estreia, 5 vezes mais rápido que o Wi-Fi 6 O sistema Hongmeng está prestes a se tornar independente e muitas universidades criaram “aulas de Hongmeng” Zhihui A empresa iniciante de junho refinancia, o valor ultrapassa 600 milhões de yuans e a avaliação pré-monetária é de 3,5 bilhões de yuans A versão para PC do Quark Browser inicia testes internos Assistente de código AI é popular e as classificações de linguagem de programação são todas Não há nada que você possa fazer O modem 5G e a tecnologia de radiofrequência do Mate 60 Pro estão muito à frente MariaDB divide SkySQL e é estabelecida como uma empresa independente Xiaomi responde à declaração de plágio “keel pivot” de Yu Chengdong da Huawei
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/u/4169309/blog/10322277
Recomendado
Clasificación