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
. PropertyType
BINARY
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