Cách nhanh chóng tìm kiếm thông qua một danh sách rất lớn các chuỗi / bản ghi trên cơ sở dữ liệu


32

Tôi có một vấn đề sau: Tôi có một cơ sở dữ liệu chứa hơn 2 triệu hồ sơ. Mỗi bản ghi có một trường chuỗi X và tôi muốn hiển thị danh sách các bản ghi cho trường X chứa một chuỗi nhất định. Mỗi bản ghi có kích thước khoảng 500 byte.

Để làm cho nó cụ thể hơn: trong GUI của ứng dụng của tôi, tôi có một trường văn bản nơi tôi có thể nhập một chuỗi. Phía trên trường văn bản tôi có một bảng hiển thị các bản ghi (N đầu tiên, ví dụ 100) khớp với chuỗi trong trường văn bản. Khi tôi nhập hoặc xóa một ký tự trong trường văn bản, nội dung bảng phải được cập nhật nhanh chóng.

Tôi tự hỏi nếu có một cách hiệu quả để làm điều này bằng cách sử dụng các cấu trúc chỉ mục và / hoặc bộ nhớ đệm phù hợp. Như đã giải thích ở trên, tôi chỉ muốn hiển thị N mục đầu tiên phù hợp với truy vấn. Do đó, đối với N đủ nhỏ, việc tải các mục phù hợp từ cơ sở dữ liệu không phải là vấn đề lớn. Bên cạnh đó, các mục lưu trữ trong bộ nhớ chính có thể giúp truy xuất nhanh hơn.

Tôi nghĩ vấn đề chính là làm thế nào để tìm thấy các mục phù hợp một cách nhanh chóng, được đưa ra chuỗi mẫu. Tôi có thể dựa vào một số cơ sở DBMS không, hoặc tôi phải tự xây dựng một số chỉ mục trong bộ nhớ? Có ý kiến ​​gì không?

CHỈNH SỬA

Tôi đã chạy thử nghiệm đầu tiên. Tôi đã chia các bản ghi thành các tệp văn bản khác nhau (tối đa 200 bản ghi cho mỗi tệp) và đặt các tệp vào các thư mục khác nhau (Tôi đã sử dụng nội dung của một trường dữ liệu để xác định cây thư mục). Tôi kết thúc với khoảng 50000 tệp trong khoảng 40000 thư mục. Tôi đã chạy Lucene để lập chỉ mục các tập tin. Tìm kiếm một chuỗi với chương trình demo Lucene khá nhanh. Việc chia tách và lập chỉ mục mất vài phút: điều này hoàn toàn chấp nhận được đối với tôi vì đây là một tập dữ liệu tĩnh mà tôi muốn truy vấn.

Bước tiếp theo là tích hợp Lucene trong chương trình chính và sử dụng các lần truy cập được Lucene trả về để tải các bản ghi liên quan vào bộ nhớ chính.


2
2 triệu bản ghi * 500 byte = 1 GB dữ liệu. Đó là rất nhiều dữ liệu để tìm kiếm, cho dù bạn đi theo hướng nào - mỗi giá trị của X có khả năng là duy nhất hay bạn sẽ có nhiều bản ghi có cùng giá trị X?

1
Đó cũng sẽ là rất nhiều dữ liệu để cố lưu trữ trong bộ nhớ dưới dạng bộ đệm để truy xuất nhanh. Điều đó sẽ tương đương với hơn 1GB mỗi phiên người dùng.
maple_shaft

Nhận xét trước đây của tôi giả định một ứng dụng web. Đây có phải là một ứng dụng web?
maple_shaft

Nó là một ứng dụng máy tính để bàn. Giá trị trong hồ sơ không nhất thiết phải là duy nhất. Ngoài ra, tôi đang tìm kiếm chuỗi con không cho một kết hợp chính xác.
Giorgio

@maple_shaft: Tôi sẽ chỉ lưu trữ các bản ghi mà tôi đã truy cập gần đây. Nếu tôi thay đổi chuỗi truy vấn và một bản ghi vẫn khớp, nó vẫn nằm trong bộ đệm.
Giorgio

Câu trả lời:


20

Thay vì đặt dữ liệu của bạn bên trong DB, bạn có thể giữ chúng dưới dạng một bộ tài liệu (tệp văn bản) riêng biệt và giữ liên kết (đường dẫn / url, v.v.) trong DB.

Điều này rất cần thiết bởi vì, truy vấn SQL theo thiết kế sẽ rất chậm cả trong tìm kiếm chuỗi con cũng như truy xuất.

Bây giờ, vấn đề của bạn được đặt ra là, phải tìm kiếm các tệp văn bản chứa tập hợp chuỗi. Có hai khả năng ở đây.

  1. Khớp chuỗi phụ Nếu các đốm văn bản của bạn là một từ đơn hoặc từ (không có bất kỳ khoảng trắng nào) và bạn cần tìm kiếm chuỗi phụ tùy ý trong đó. Trong những trường hợp như vậy, bạn cần phân tích từng tệp để tìm các tệp phù hợp nhất có thể. Người ta sử dụng các thuật toán như thuật toán Boyer Moor. Xem cái nàycái này để biết chi tiết. Điều này cũng tương đương với grep - vì grep sử dụng những thứ tương tự bên trong. Nhưng bạn vẫn có thể kiếm được ít nhất 100+ grep (trường hợp xấu nhất là 2 triệu) trước khi quay lại.

  2. Tìm kiếm được lập chỉ mục. Ở đây bạn giả sử rằng văn bản chứa tập hợp các từ và tìm kiếm bị giới hạn ở độ dài từ cố định. Trong trường hợp này, tài liệu được lập chỉ mục trên tất cả các lần xuất hiện của từ. Điều này thường được gọi là "Tìm kiếm toàn văn". Có một số thuật toán để làm điều này và số lượng các dự án nguồn mở có thể được sử dụng trực tiếp. Nhiều người trong số họ, cũng hỗ trợ tìm kiếm thẻ hoang dã, tìm kiếm gần đúng, v.v. như dưới đây:
    a. Lucene Apache: http://lucene.apache.org/java/docs/index.html
    b. OpenFTS: http://openraft.sourceforge.net/
    c. Nhân sư http://sphinxsearch.com/

Rất có thể nếu bạn cần "từ cố định" làm truy vấn, cách tiếp cận hai sẽ rất nhanh và hiệu quả.


2
Đây là một khái niệm thú vị nhưng dường như không có khả năng nhà phát triển có thể dễ dàng tìm kiếm thông qua 1GB dữ liệu văn bản nhanh hơn và hiệu quả hơn so với công cụ cơ sở dữ liệu. Những người thông minh hơn bạn và tôi đã làm việc với các trình tối ưu hóa truy vấn để làm điều đó và hơi ngây thơ khi nghĩ rằng bạn bằng cách nào đó có thể làm điều đó hiệu quả hơn.
maple_shaft

4
@maple_shaft Các ví dụ tôi đã đưa ra không phải là các công cụ cơ sở dữ liệu RDBMS. Chúng giống như "công cụ tìm kiếm" hơn nếu bạn muốn gọi nó. Có một sự khác biệt lớn về mặt khái niệm giữa việc chọn một danh sách ra khỏi một chỉ mục (hoặc bảng băm) so với việc tìm kiếm thông qua 1GB dữ liệu mỗi lần truy vấn. Vì vậy, những gì tôi đang đề nghị không phải là một điều chỉnh nhỏ.
Dipan Mehta

Đây có vẻ là một ý tưởng thú vị nhưng tôi tự hỏi làm thế nào nó sẽ hoạt động. Tôi sẽ có hơn 2 000 000 tệp, mỗi tệp có kích thước khoảng nửa kilobyte. Hoặc bạn đang đề nghị có nhiều hơn một bản ghi cho mỗi tệp? Điều gì sẽ là sự khác biệt wrt một cơ sở dữ liệu?
Giorgio

Tôi không tin rằng điều này nhất thiết sẽ thực hiện tốt hơn bất kỳ chỉ số SQL fulltext nào.
Kirk Broadhurst

@Giorgio - vâng, đó là cách các công cụ tìm kiếm toàn văn sẽ hoạt động. Sự khác biệt chính ở đây là các trang được lập chỉ mục trước so với tìm kiếm trong bộ nhớ (một lần nữa cho mỗi lần truy vấn đến).
Dipan Mehta

21

Công nghệ bạn đang tìm kiếm là lập chỉ mục toàn văn. Hầu hết RDBMS có một số loại khả năng tích hợp có thể hoạt động ở đây hoặc bạn có thể sử dụng một cái gì đó như Lucene nếu bạn muốn lấy fancier và / hoặc chỉ chạy nó trong bộ nhớ.


1
Theo tôi, các tùy chọn toàn văn bản trong bất kỳ RDBMS nào là một cách giải quyết để làm cho nó thực hiện một cái gì đó mà nó không được thiết kế cho: "tìm kiếm trong một số dữ liệu không liên quan đến cấu trúc". Nếu bạn đang xây dựng một searchengine, bạn không sử dụng RDBMS. Nó có thể hoạt động cho các bộ dữ liệu nhỏ nhưng lakcs bất kỳ loại tỷ lệ. Tìm kiếm thông qua hàng đống dữ liệu phi cấu trúc không phải là một cái đinh, vì vậy đừng sử dụng búa. Sử dụng các công cụ thích hợp cho công việc.
Pieter B

8

Bạn đã xem xét một trie ? Về cơ bản, bạn xây dựng một cây bằng cách sử dụng các tiền tố phổ biến, vì vậy tất cả các từ bắt đầu bằng cùng một chữ cái là con của cùng một nút. Nếu bạn sẽ hỗ trợ kết hợp trên bất kỳ chuỗi con nào, thì bạn sẽ phải tạo một số loại chỉ mục được thẩm thấu và xây dựng bộ ba của bạn từ đó. Điều đó có thể kết thúc thổi yêu cầu lưu trữ của bạn ra ngoài, mặc dù.


1
VÂNG! Tôi đã suy nghĩ về cấu trúc cây và tôi nhớ rằng có một thứ tương tự có thể phù hợp với tôi, nhưng tôi không nhớ bộ ba vì tôi chưa bao giờ sử dụng chúng. Về yêu cầu lưu trữ: hãy nhớ rằng tôi chỉ cần truy xuất N mục nhập đầu tiên (ví dụ: N = 100) vì sẽ không có ý nghĩa gì khi điền vào bảng với 20000 lần truy cập. Vì vậy, mỗi nút của bộ ba sẽ trỏ đến tối đa N mục. Ngoài ra, tôi quên đề cập rằng tôi cần truy cập nhanh nhưng tôi không cần cập nhật nhanh, vì dữ liệu chỉ được tải một lần. Ý tưởng trie về một chỉ số hoán vị thực sự có thể làm việc!
Giorgio

1
Câu trả lời hay nhưng như bạn lưu ý, một bộ ba rất phù hợp để bắt đầu từ của bạn nhưng sẽ nhanh chóng trở nên phức tạp và rất lớn nếu khớp với bất kỳ chuỗi con nào ...
Kirk Broadhurst

Là một thử nghiệm đầu tiên, tôi đã cố gắng xây dựng tập hợp tất cả các chuỗi con xuất hiện trong chuỗi mà tôi phải tìm kiếm, nếu tôi hiểu chính xác, tương ứng với các đường dẫn của bộ ba. Tôi đã có một ngoại lệ hết bộ nhớ (với 256M heap cho JVM) ở các chuỗi con có độ dài 6. Vì vậy, tôi sợ giải pháp này không khả thi, trừ khi tôi làm sai.
Giorgio

5

Tôi muốn thêm vào câu trả lời của Wyatt Barnett rằng một giải pháp RDBMS với lập chỉ mục toàn văn bản trên cột thích hợp sẽ hoạt động, nhưng nếu bạn muốn sử dụng bộ đệm cục bộ của các bản ghi được tìm nạp trước đó thì bạn cần có kế hoạch sử dụng các bản ghi được lưu trong bộ nhớ cache này để lợi thế của bạn.

Một tùy chọn là thu thập các định danh duy nhất của các bản ghi này mà bạn KHÔNG THỂ truy xuất từ ​​truy vấn và bao gồm chúng, có thể trong một NOT INhoặc a NOT EXISTS.

Mặc dù vậy, cần thận trọng, sử dụng NOT INhoặc NOT EXISTScó xu hướng không rẻ và CÓ THỂ ảnh hưởng tiêu cực đến hiệu suất truy vấn hoặc kế hoạch truy vấn của bạn tùy thuộc vào công cụ cơ sở dữ liệu nào bạn đang sử dụng. Chạy một kế hoạch giải thích cho truy vấn cuối cùng của bạn để đảm bảo rằng tất cả các chỉ mục của bạn trên các cột bị ảnh hưởng đang được sử dụng.

Việc so sánh hiệu suất giữa hai phương pháp để xem cái nào nhanh hơn cũng không hại gì. Bạn có thể ngạc nhiên khi phát hiện ra rằng việc duy trì bộ đệm cục bộ và lọc chúng khỏi truy vấn của bạn một cách rõ ràng có thể có hiệu suất kém hơn so với truy vấn được tinh chỉnh tìm nạp tất cả các bản ghi.


maple_shaft và @Wyatt Barnett: Cảm ơn rất nhiều về những gợi ý. Tôi sẽ phải làm một số đọc và thử các giải pháp khác nhau. Không phải tất cả các cơ sở dữ liệu đều hỗ trợ lập chỉ mục đầy đủ, MySQL (mà tôi hiện đang sử dụng) không ( dev.mysql.com/doc/refman/5.5/en/fulltext-search.html ). Tôi sẽ cố gắng làm một số bài kiểm tra và sau đó báo cáo ở đây.
Giorgio

2

Chỉ trong trường hợp bạn bị mất nó. Nếu bạn sử dụng Lucene cho cơ sở dữ liệu của bạn thay vì tìm kiếm văn bản được hỗ trợ trong DB, bạn sẽ phải cực kỳ cẩn thận khi thực hiện sửa đổi đối với DB của mình. Làm thế nào để bạn chắc chắn rằng bạn có thể có tính nguyên tử khi bạn phải thay đổi cả DB và tài nguyên bên ngoài (Lucene)? Vâng, nó có thể được thực hiện, nhưng sẽ có rất nhiều công việc.

Nói tóm lại, bạn đang mất hỗ trợ giao dịch DB nếu bạn đặt Lucene vào lược đồ dữ liệu của mình.


1
Dù sao, vấn đề như đã nêu dường như không phù hợp với RDMS.
Pieter B

1

Bạn đã xem Nhân sư chưa? http://sphinxsearch.com nếu bạn có thể sử dụng công cụ của bên thứ 3 thì đây sẽ là lý tưởng cho những gì bạn đang cố gắng đạt được, nó hiệu quả hơn khi tìm kiếm toàn văn bản so với bất kỳ RDBMS nào tôi đã sử dụng.


3
và bỏ phiếu là cho?
twigg

1

Điều hơi lạ là không có câu trả lời nào đưa ra thuật ngữ "chỉ số đảo ngược" , công nghệ làm nền tảng cho tất cả các giải pháp tương tự như Apache Lucene và các giải pháp khác.

Chỉ mục đảo ngược là ánh xạ từ các từ thành tài liệu ("chỉ mục đảo ngược mức ghi") hoặc thậm chí các vị trí từ chính xác trong tài liệu ("chỉ mục đảo ngược mức từ").

Các hoạt động logic AND và OR là tầm thường để thực hiện. Nếu bạn có vị trí từ chính xác, có thể tìm các từ liền kề, do đó có thể thực hiện tìm kiếm cụm từ.

Vì vậy, hãy nghĩ về một chỉ mục chứa các bộ dữ liệu (từ, tệp, vị trí). Khi bạn có ví dụ ("đảo ngược", "foo.txt", 123) thì bạn chỉ cần kiểm tra xem ("index", "foo.txt", 124) có phải là một phần của chỉ mục để tìm kiếm cụm từ đầy đủ "chỉ mục đảo ngược" không .

Mặc dù tôi không khuyên bạn nên triển khai lại một công cụ tìm kiếm toàn văn từ đầu, nhưng thật hữu ích khi biết các công nghệ như Apache Lucene hoạt động như thế nào.

Vì vậy, khuyến nghị của tôi là tìm hiểu cách các chỉ mục đảo ngược hoạt động và chọn một công nghệ sử dụng chúng như Apache Lucene. Sau đó, bạn ít nhất có một sự hiểu biết vững chắc về những gì có thể được thực hiện và những gì không thể được thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.