2009-11-25 22 views
6

Tengo una cadena de 18 caracteres que necesito convertir en una única larga (en Java). Una cadena de ejemplo sería: AAA2aNAAAAAAADnAAACómo convertir una Cadena de 18 Caracteres en una ID Única?

de mi secuencia es en realidad un ROWID de Oracle, por lo que se puede dividir si es necesario, ver: http://download-uk.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#CNCPT713

El número de larga genera, (1) debe ser único, como dos resultados no pueden apuntar a la misma fila de la base de datos y (2) debe ser reversible, entonces puedo recuperar la cadena ROWID desde el principio?

Cualquier sugerencia sobre un algoritmo para usar sería bienvenida.

pregunta Oracle foro sobre esto desde hace unos años: http://forums.oracle.com/forums/thread.jspa?messageID=1059740

Ro

+0

Hasta ahora Esto es casi imposible. Si lo hubiera, el factor de carga de hashtable se ha apagado. Sin embargo, permite que alguien tenga alguna idea. – DKSRathore

Respuesta

0

encontrado una manera de extraer el ROWID de una manera diferente de la base de datos ....

 
SQL> select DBMS_ ROWID.ROWID_ TO_RESTRICTED(ROWID, 1) FROM MYTABLE;

0000EDF4.0001.0000 0000EDF4.0002.0000 0000EDF4.0004.0000 0000EDF4.0005.0000 0000EDF4.0007.0000 0000EDF5.0000.0000 0000EDF5.0002.0000 0000EDF5.0003.0000

después convertirlo a un número de este modo:

 
final String hexNum = rowid.replaceAll("\.", ""); 
final long lowerValue = Long.parseLong(hexNum.substring(1), 16); 
long upperNibble = Integer.parseInt(hexNum.substring(0, 1), 16); 
if (upperNibble >= 8) { 
    //Catch Case where ROWID > 8F000000.0000.0000 
    upperNibble -= 8; 
    return -(9223372036854775807L - (lowerValue - 1 + (upperNibble << 60))); 
} else { 
    return (lowerValue + (upperNibble << 60)); 
} 

luego revertir ese número volver al formato de cadena como lo siguiente:

 
String s = Long.toHexString(featureID); 
//Place 0's at the start of the String making a Strnig of size 16 
s = StringUtil.padString(s, 16, '0', true); 
StringBuffer sb = new StringBuffer(s); 
sb.insert(8, '.'); 
sb.insert(13, '.');

return sb.toString();

Saludos a todas las respuestas.

11

No se puede, con esos requisitos.

18 caracteres de (suponiendo) letras mayúsculas y minúsculas tiene 56 o aproximadamente 2,93348915 × 103 combinaciones. Esto es (camino) más que las combinaciones aproximadas de 1.84467441 × 10 disponibles entre 64 bits.

ACTUALIZACIÓN: Tenía la combinatoria mal, heh. Mismo resultado sin embargo.

+0

De acuerdo con la documentación, es una codificación base 64, que usa a-z, A-Z, 0-9 y también + y /. Por lo tanto, es aún peor :-) – Joey

+0

Si los dígitos están permitidos, entonces haga que 18^((2 * 26) +10) empeore nuevamente. – Liam

+0

Si, sin embargo, la cadena de 18 caracteres puede descomponerse en sus componentes, así que me preguntaba si se podía hacer algo debido a que: AAA2aNAAAAAAADnAAA = AAA2aN - AAA - AAAADn - AAA Además, la garantía de la unicidad en realidad, solo tendría que cubrir como máximo 100 millones de casos ... ¡Es poco probable que tenga una tabla de base de datos más grande que eso! –

-1

Esto suena ... repulsivo, pero no conozco tu contexto, por lo que intento no juzgar. 8)

¿Ha considerado convertir los caracteres de la cadena en sus equivalentes ASCII?

ADDENDUM: Por supuesto, es necesario truncar caracteres semi-superflores para que quepan, lo que suena como una opción que puede tener de los comentarios.

+0

Sí .... Esto salió antes bien ... http://forums.oracle.com/forums/thread.jspa?messageID=1059740 –

4

Su cadena de 18 caracteres que representa una codificación de base 64 representa un total de 108 bits de información, que es casi el doble que la longitud de 64. Tenemos un pequeño problema aquí si queremos representar todas las claves posibles y tener la representación sea reversible.

La secuencia se puede dividir en 4 números con bastante facilidad. Cada uno de esos 4 números representa algo: un número de bloque, un desplazamiento en ese bloque, lo que sea. Si logra establecer límites superiores en las cantidades subyacentes de modo que sepa que no se producirán números más grandes (es decir, si encuentra una manera de identificar al menos 44 de esos bits que siempre serán 0), puede asignar el resto a una largo, reversible.

Otra posibilidad sería relajar el requisito de que el equivalente sea un long. ¿Qué tal un BigInteger? Eso lo haría fácil.

+0

"¿Qué tal un BigInteger?" O dos largos. –

+0

Lo consideré brevemente, pero dos largos es asqueroso, IMO. Estamos trabajando en lenguajes OO para que podamos tratar valores únicos como entidades únicas. Para números suficientemente pequeños, BigInteger * es * efectivamente dos largos, pero está envuelto en un paquete coherente. –

+0

Claro, es solo que no vamos a hacer ninguna matemática. Probablemente definiría una clase con dos campos 'largos' (" tophalf "y" bottomhalf "o lo que sea) y métodos para convertir a/desde cadenas. Pero realmente depende de por qué el interlocutor (cree que) necesita un largo. Si solo tiene 8 bytes de almacenamiento, entonces ni BigInteger ni dos largos son posibles. –

2

Asumo que es una cadena alfanumérica entre mayúsculas y minúsculas, y así elaborado a partir del conjunto [a-zA-Z0-9]*

En ese caso hay que

26 + 26 + 10 = 62 

valores posibles para cada carácter.

62 < 64 = 2^6 

En otras palabras, necesita (al menos) 6 bits para almacenar cada uno de los 18 caracteres de la clave.

6 * 18 = 108 bits 

para almacenar toda la cadena de forma exclusiva.

108 bits = (108/8) = 13.5 bytes. 

Por lo tanto, siempre y cuando el tipo de datos puede almacenar al menos 13,5 bytes entonces usted puede de manera bastante simple definir una asignación:

  1. Mapa de ASCII prima para cada personaje para una representación usando solamente 6 bits de
  2. Concatenate los 18 representaciones reducidas a un valor de byte sinlde 14
  3. moldeada esto a su valor final de los datos

Obviamente, Java tiene nada más que un byte long de 8 bytes. Por lo tanto, si tiene que usar un long, es NOT posible asignar un mapa exclusivo de las cadenas, a menos que haya algo más que reduzca el espacio de las cadenas de entrada válidas.

+0

En realidad es una codificación base 64 por lo que también incluye '+' y '/'. –

+0

OK, eso todavía le permite encajar en 6 bits por carácter, aunque –

4

Simplemente cree un mapa (diccionario/hashtable) que mapee las cadenas ROWID a una longitud (incrementada). Si conserva dos de esos diccionarios y los resume en una buena clase, tendrá una búsqueda bidireccional entre las cadenas y los ID largos.

Pseudocódigo:

class BidirectionalLookup: 
    dict<string, long> stringToLong 
    dict<long, string> longToString 
    long lastId 

    addString(string): long 
     newId = atomic(++lastId) 
     stringToLong[string] = newId 
     longToString[newId] = string 
     return newId 

    lookUp(string): long 
     return stringToLong[string] 

    lookUp(long): string 
     return longToString[long] 
+0

Esto es lo que implementé previamente (después de la investigación inicial, vea el enlace del foro de Oracle). ¡El problema es que este hashmap caché ha crecido por encima del límite superior para el tamaño de un hashmap! Por lo tanto, se está investigando de nuevo –

+0

http://forums.oracle.com/forums/thread.jspa?messageID=1059740 –

+0

¿por qué no utilizar una tabla en su base de datos para esto? –

1

En teoría, no se puede representar en una larga ROWID (8 bytes). Sin embargo, dependiendo del tamaño de sus bases de datos (el servidor completo, no solo su tabla), es posible que pueda codificarlo por mucho tiempo.

Este es el diagrama de ROWID,

OOOOOO-FFF-BBBBBB-RRR 

donde O es de objeto. F es FileNo. B es Bloque y R es Número de Fila. Todos ellos están codificados en Base64. Como puede ver O & B puede tener 36 bits y B & R puede tener 18.

Si su base de datos no es grande, puede usar 2 bytes para cada parte. Básicamente, su ID de objeto y el número de bloque estarán limitados a 64 KB. Nuestro DBA cree que nuestra base de datos tiene que ser de una magnitud mucho mayor para que podamos acercarnos a estos límites.

Le sugiero que busque el máximo de cada parte en su base de datos y vea si está cerca. No usaría mucho si están cerca del límite.

+0

Insertar nuevas filas mucho después de que una tabla en creada pueda dar como resultado ROWIDs radicalmente diferentes para las nuevas filas, por lo que realmente no podemos seguir esa ruta. –

Cuestiones relacionadas