2009-11-25 58 views
6

Tôi có một chuỗi ký tự 18 mà tôi cần phải chuyển đổi thành một chuỗi dài duy nhất (trong Java). Chuỗi mẫu sẽ là: AAA2aNAAAAAAADnAAALàm thế nào để chuyển đổi một chuỗi ký tự 18 thành một ID duy nhất?

Chuỗi tôi thực sự là một Oracle ROWID, vì vậy nó có thể được chia nhỏ nếu nhu cầu được, xem: http://download-uk.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#CNCPT713

Số dài tạo ra, (1) Phải là duy nhất, vì không có hai kết quả nào có thể trỏ đến cùng một hàng cơ sở dữ liệu và (2) Phải có thể đảo ngược, vì vậy tôi có thể lấy lại chuỗi ROWID từ lâu?

Mọi đề xuất về thuật toán sử dụng sẽ được hoan nghênh.

Oracle diễn đàn câu hỏi về vấn đề này từ một vài năm trước đây: http://forums.oracle.com/forums/thread.jspa?messageID=1059740

Ro

+0

Cho đến bây giờ Điều này gần như không thể. Nếu nó đã có yếu tố tải từ hashtable đã đi ra ngoài. Tuy nhiên, cho phép nếu ai đó có bất kỳ ý tưởng nào .. – DKSRathore

Trả lời

0

Tìm thấy một cách để trích xuất các ROWID một cách khác nhau từ cơ sở dữ liệu ....

 
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

Sau đó chuyển nó sang một số như sau:

 
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)); 
} 

Sau đó đảo ngược số đó quay lại định dạng Chuỗi như vậy:

 
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();

Chúc mừng tất cả các câu trả lời.

11

Bạn không có thể, với những yêu cầu này.

18 ký tự của (giả định) chữ hoa và chữ thường có 56 hoặc khoảng 2.93348915 × 103 kết hợp. Đây là (cách) nhiều hơn khoảng 1.84467441 × 10 kết hợp có sẵn trong số 64 bit.

CẬP NHẬT: Tôi đã có tổ hợp sai, heh. Cùng một kết quả mặc dù.

+0

Theo tài liệu, đó là mã hóa cơ bản 64, sử dụng a-z, A-Z, 0-9 cũng như + và /. Vì vậy, nó thậm chí còn tồi tệ hơn :-) – Joey

+0

Nếu chữ số được phép, sau đó làm cho rằng 18^((2 * 26) 10), tệ hơn nữa. – Liam

+0

Vâng, tuy nhiên chuỗi 18 ký tự có thể được chia nhỏ thành các thành phần của nó, vì vậy tôi đã tự hỏi nếu có bất kỳ điều gì có thể được thực hiện vì: AAA2aNAAAAAAADnAAA = AAA2aN - AAA - AAAADn - AAA Ngoài ra, đảm bảo tính duy nhất về mặt thực tế sẽ chỉ bao gồm tối đa 100 triệu trường hợp .... Không có khả năng có một bảng cơ sở dữ liệu lớn hơn thế! –

-1

Điều này nghe có vẻ ... icky, nhưng tôi không biết bối cảnh của bạn để cố gắng không vượt qua phán xét. 8)

Bạn đã xem xét chuyển đổi các ký tự trong chuỗi thành các phần tử ASCII tương đương của chúng?

THÊM: Tất nhiên, yêu cầu cắt bớt các ký tự bán siêu phù hợp, có vẻ như một tùy chọn bạn có thể có từ nhận xét.

+0

Vâng .... Điều này đã xảy ra trước khi ổn ... http://forums.oracle.com/forums/thread.jspa?messageID=1059740 –

4

Chuỗi 18 ký tự đại diện cho mã hóa 64 cơ sở đại diện cho tổng số 108 bit thông tin, gần bằng gấp đôi số bit dài 64. Chúng tôi có một vấn đề ở đây nếu chúng tôi muốn đại diện cho mọi khóa có thể có biểu diễn có thể đảo ngược.

Chuỗi có thể được chia thành 4 số dễ dàng đủ. Mỗi trong số 4 con số đó đại diện cho một cái gì đó - một số khối, một sự bù đắp trong khối đó, bất cứ điều gì. Nếu bạn quản lý để thiết lập giới hạn trên cho số lượng bên dưới sao cho bạn biết số lớn hơn sẽ không xảy ra (ví dụ: nếu bạn tìm cách xác định ít nhất 44 bit đó sẽ luôn bằng 0), thì bạn có thể ánh xạ phần còn lại vào dài, đảo ngược.

Một khả năng khác là thư giãn yêu cầu tương đương là long. Làm thế nào về một BigInteger? Điều đó sẽ làm cho nó dễ dàng.

+0

"Làm thế nào về một BigInteger?" Hoặc hai thời gian dài. –

+0

Tôi đã nhanh chóng xem xét điều đó, nhưng hai thời gian dài là yucky, IMO. Chúng tôi đang làm việc trong các ngôn ngữ OO để chúng tôi có thể coi các giá trị đơn lẻ là các thực thể đơn lẻ. Đối với các con số đủ nhỏ, BigInteger * có hiệu quả là hai thời gian dài, nhưng nó được gói lại thành một gói mạch lạc. –

+0

Chắc chắn, nó chỉ là chúng tôi sẽ không làm bất kỳ toán học. Tôi có thể định nghĩa một lớp với hai trường 'long' (" tophalf "và" bottomhalf "hoặc bất kỳ thứ gì) và các phương thức để chuyển đổi thành/từ chuỗi. Nhưng thực sự nó phụ thuộc vào lý do tại sao người hỏi (nghĩ rằng anh ta) cần một thời gian dài. Nếu anh ta chỉ có 8 byte dung lượng lưu trữ, thì cả BigInteger lẫn hai thời gian đều không thể thực hiện được. –

2

Tôi giả định đó là một chuỗi chữ-số case-insensitive, và do đó được rút ra từ tập [a-zA-Z0-9]*

Trong trường hợp đó bạn có

26 + 26 + 10 = 62 

giá trị có thể cho mỗi nhân vật.

62 < 64 = 2^6 

Nói cách khác bạn cần (ít nhất) 6 bit để lưu trữ mỗi 18 ký tự của khóa.

6 * 18 = 108 bits 

để lưu toàn bộ chuỗi duy nhất.

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

Do đó càng lâu càng kiểu dữ liệu của bạn có thể lưu trữ ít nhất 13,5 byte sau đó bạn có thể khá đơn giản xác định một ánh xạ:

  1. Map từ ASCII liệu cho mỗi nhân vật là một đại diện sử dụng chỉ có 6 bit
  2. cONCATENATE tất cả 18 cơ quan đại diện giảm đến một giá trị byte sinlde 14
  3. Cast này để giá trị dữ liệu cuối cùng của bạn

Rõ ràng Java không có gì hơn 8 byte long. Vì vậy, nếu bạn phải sử dụng long thì đó là KHÔNG có thể ánh xạ duy nhất các chuỗi, trừ khi có điều gì đó khác làm giảm không gian của các chuỗi đầu vào hợp lệ.

+0

Nó thực sự là một mã hóa cơ sở 64 vì vậy nó cũng bao gồm '+' và '/'. –

+0

OK, điều đó vẫn cho phép nó vừa với 6 bit cho mỗi ký tự mặc dù –

4

Chỉ cần tạo bản đồ (từ điển/có thể bắt đầu) ánh xạ các chuỗi ROWID đến một (tăng dần). Nếu bạn giữ hai từ điển như vậy và bọc chúng trong một lớp học tốt đẹp, bạn sẽ có một tra cứu hai chiều giữa các chuỗi và các ID dài.

Mã giả:

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

Đây là những gì tôi đã thực hiện trước đó (sau khi điều tra ban đầu - xem liên kết Diễn đàn Oracle). Vấn đề là bộ đệm băm này đã tăng lên trên giới hạn trên cho kích thước của băm! Do đó việc điều tra lại được kiểm tra –

+0

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

+0

tại sao không sử dụng bảng trong cơ sở dữ liệu của bạn cho điều này? –

1

Về mặt lý thuyết, bạn không thể đại diện ROWID trong một chặng đường dài (8 byte). Tuy nhiên, tùy thuộc vào kích thước của cơ sở dữ liệu của bạn (toàn bộ máy chủ, không chỉ bảng của bạn), bạn có thể mã hóa nó thành một thời gian dài.

Dưới đây là cách bố trí của ROWID,

OOOOOO-FFF-BBBBBB-RRR 

đâu O là ObjectId. F là FileNo. B là khối và R là số hàng. Tất cả đều được mã hóa Base64. Như bạn có thể thấy O & B có thể có 36 bit và B & R có thể có 18.

Nếu cơ sở dữ liệu của bạn không lớn, bạn có thể sử dụng 2 byte cho mỗi phần. Về cơ bản, ObjectId của bạn và số khối sẽ được giới hạn đến 64K. DBA của chúng tôi tin rằng cơ sở dữ liệu của chúng tôi phải lớn hơn một vài độ lớn để chúng tôi đạt được các giới hạn này.

Tôi khuyên bạn nên tìm tối đa từng phần trong cơ sở dữ liệu của mình và xem bạn có ở gần không. Tôi sẽ không sử dụng lâu nếu họ ở bất cứ đâu gần giới hạn.

+0

Chèn hàng mới dài sau khi bảng được tạo có thể dẫn đến ROWID hoàn toàn khác nhau cho các hàng mới, vì vậy chúng tôi không thể thực sự đi theo tuyến đường đó. –

Các vấn đề liên quan