Quais são as opções para o utilizador de geração alfa amigável IDs numéricos (como id negócio, SKU)

StackOverflow https://stackoverflow.com/questions/217253

  •  03-07-2019
  •  | 
  •  

Pergunta

Aqui estão os requisitos:

Deve ser alfanumérico, 8-10 caracteres de modo que seja fácil de usar. Estes serão armazenados como chaves únicas em banco de dados. Eu estou usando GUIDs como chaves primárias assim uma opção para guids usar para gerar estes IDs exclusivos seria preferível.

Eu estou pensando sobre as linhas de uma base-n conversor que leva um Guid e convertidos para uma string única de 8 caracteres.

Curto, algoritmo leve preferido como seria chamado com bastante frequência.

Foi útil?

Solução

Você pode considerar base 36. em que ele pode fazer letras e números. Considere a remoção I (olho) e O (Oh) do seu conjunto para que eles não se misturam com 1 (um) e 0 (zero). Algumas pessoas podem queixar-2 e Z também.

Outras dicas

8 characters - perfectly random - 36^8 = 2,821,109,907,456 combinations
10 characters - perfectly random - 36^10 = 3,656,158,440,062,976 combinations
GUID's - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations

é um GUID exclusivo 100% do tempo? [Stackoverflow]

O problema com seu GUID -> conversão de caracteres; enquanto o GUID é estatisticamente único, tomando qualquer subconjunto você diminui aleatoriedade e aumentar a chance de colisões. Você certamente não quer criar não unqiue SKU.


Solução 1:

Criar SKU utilizando dados relevantes para as regras de objetos e de negócios.

i. Há probabilidade de ser uma pequena combinação de atributos que faz com que um objeto único (uma chave natural) . Combine os elementos da chave natural, codificar e comprimi-los para criar um SKU. Muitas vezes, tudo que você precisa é um campo de data e hora (ou seja CreationDate) e algumas outras propriedades para conseguir isso. É provável que você tem um monte de buracos na criação sku, mas de SKU são mais relevantes para os usuários.

hipoteticamente:

Wholesaler, product name, product version, sku
Amazon,     IPod Nano,    2.2,             AMIPDNN22
BestBuy,    Vaio,         3.2,             BEVAIO32

Solução 2:

Um método que as reservas de uma gama de números, e depois prossegue para libertá-los sequencialmente, e nunca retorna o mesmo número de vezes. Você ainda pode acabar com buracos no intervalo. Provável que você não precisa gerar o suficiente SKU à matéria, mas garantir que seus requisitos permitem isso.

Uma implementação é ter uma tabela key em um banco de dados que tem um contador. O contador é incrementado em uma transação. Um ponto importante é que, em vez de por uma incrementação, o método em software agarra um bloco. pseudo-c # -Code é a seguinte.

-- what the key table may look like
CREATE TABLE Keys(Name VARCHAR(10) primary key, NextID INT)
INSERT INTO Keys Values('sku',1)

// some elements of the class
public static SkuKeyGenerator 
{
    private static syncObject = new object();
    private static int nextID = 0;
    private static int maxID = 0;
    private const int amountToReserve = 100;

    public static int NextKey()
    {
        lock( syncObject )
        {
            if( nextID == maxID )
            {
                ReserveIds();
            }
            return nextID++;
        }
    }
    private static void ReserveIds()
    {
        // pseudocode - in reality I'd do this with a stored procedure inside a transaction,
        // We reserve some predefined number of keys from Keys where Name = 'sku'
        // need to run the select and update in the same transaction because this isn't the only
        // method that can use this table.
        using( Transaction trans = new Transaction() ) // pseudocode.
        {
             int currentTableValue = db.Execute(trans, "SELECT NextID FROM Keys WHERE Name = 'sku'");
             int newMaxID = currentTableValue + amountToReserve;
             db.Execute(trans, "UPDATE Keys SET NextID = @1 WHERE Name = 'sku'", newMaxID);

             trans.Commit();

             nextID = currentTableValue;
             maxID = newMaxID;
        }
    } 

A idéia aqui é que você reservar chaves suficientes para que o seu código não vai do banco de dados, muitas vezes, como a obtenção do intervalo de chave é uma operação cara. Você precisa ter uma boa idéia do número de chaves que você precisa reservar para equilibrar a perda de chave (reinicialização do aplicativo) versus esgotar chaves demasiado depressa e de volta para o banco de dados indo. Esta implementação simples tem nenhuma maneira de reutilizar chaves perdidas.

Porque esta implementação depende de um banco de dados e transações você pode ter aplicações rodando simultaneamente e todos gerar chaves únicas sem a necessidade de ir para o banco de dados muitas vezes.

Observe o acima é vagamente baseado em key table, página 222 de Padrões de Enterprise Application Architecture (Fowler) . O método é geralmente usado para gerar chaves primárias sem a necessidade de uma coluna de identidade de banco de dados, mas você pode ver como ele pode ser adaptado para o seu propósito.

Se você está procurando "user friendly" que você pode querer tentar usar palavras inteiras em vez de simplesmente tornando-se a curto / alfanuméricos, assim, algo como:

words = [s.strip().lower() for s in open('/usr/share/dict/canadian-english') if "'" not in s]
mod = len(words)

def main(script, guid):
    guid = hash(guid)

    print "+".join(words[(guid ** e) % mod] for e in (53, 61, 71))

if __name__ == "__main__":
    import sys
    main(*sys.argv)

Que produz uma saída como:

oranjestad+compressing+wellspring
padlock+discommoded+blazons
pt+olenek+renews

O que é divertido. Caso contrário, simplesmente dando os primeiros 8-10 caracteres do guid ou sha1 / hash MD5 do guid é provavelmente a sua melhor aposta.

A coisa mais simples que poderia funcionar é um contador que é incrementado cada vez que é necessário um valor. Oito dígitos (à esquerda com zeros à esquerda) dá-lhe 100 milhões de valores possíveis 00000000-99.999.999 (embora você possa interpor espaços ou hífens para legibilidade humana, como em 000-000-00).

Se você vai precisar de mais de 100 milhões de valores, você poderia aumentar as letras de comprimento ou de uso em posições alternadas. Usando A0A0A0A0 através Z9Z9Z9Z9 dá-lhe mais quatro e meio bilhões de valores possíveis (4,569,760,000) disponíveis. É um pouco trivial de código para tomar um inteiro longo e produzir uma codificação tal (mod 10 para o dígito mais à direita, div por 10, então mod 26 para a letra mais à direita, etc.) Se você tem a memória para queimar, a maneira mais rápida é converter o contador a uma matriz de modificação 260, e utilizar cada valor mod 260 como um índice para uma matriz de cadeias de dois caracteres ( "A0", "A1", "A2", e assim por diante através de "A9", " B0" , "B1", etc. thru "Z9").

O problema com a base 36 (mencionado em outra resposta) é que você não só tem que se preocupar com a confusão leitor de caracteres semelhantes (uma vs. I, de zero vs. O, dois Z vs., cinco vs. S), mas também sobre combinações de letras adjacentes que podem ser percebidos pelos leitores como soletrar palavras ou abreviaturas desagradáveis ??ou obsceno.

Você pode querer tentar um algoritmo CRC32 hashing. O CRC32 gera uma cadeia de 8 caracteres.

http://en.wikipedia.org/wiki/Cyclic_redundancy_check

http://textop.us/Hashing/CRC

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top