2010-02-14 45 views
27

Tôi muốn sử dụng Lucene.NET cho tìm kiếm fulltext được chia sẻ giữa hai ứng dụng: một là một ứng dụng ASP.NET MVC và ứng dụng kia là một ứng dụng giao diện điều khiển. Cả hai ứng dụng đều có nhiệm vụ tìm kiếm và cập nhật chỉ mục. Cách xử lý đồng thời?
Tôi tìm thấy một tutorial on ifdefined.com nơi trường hợp sử dụng tương tự được thảo luận. Mối quan tâm của tôi là khóa sẽ là một nút cổ chai lớn.Đồng thời trong Lucene.NET.

PS: Ngoài ra tôi nhận thấy rằng IndexSearcher sử dụng ảnh chụp nhanh chỉ mục và trong hướng dẫn được đề cập ở trên, trình tìm kiếm chỉ được tạo khi chỉ mục được cập nhật. Đây có phải là một cách tiếp cận tốt? Tôi có thể chỉ cần tạo một đối tượng tìm kiếm thông thường ở mỗi tìm kiếm và nếu có thì phí là gì?

Tôi đã tìm thấy câu hỏi có liên quan Does Lucene.Net manage multiple threads accessing the same index, one indexing while the other is searching? những gì tuyên bố rằng đồng thời liên quá trình là an toàn. Nó có nghĩa là nó không phải là điều kiện chủng tộc cho chỉ mục?

Cũng là một khía cạnh rất quan trọng. Hiệu suất hit có liên quan gì nếu chúng ta nói 10-15 chủ đề đang cố gắng cập nhật chỉ mục Lucene thông qua việc mua khóa chia sẻ được trình bày trong this solution?

Sau khi sử dụng nó vài tháng, tôi phải thêm chỉ mục mở cho tìm kiếm thường có thể tạo ngoại lệ OutOfMemory dưới CPU cao và tải bộ nhớ nếu truy vấn sử dụng sắp xếp. Chi phí hoạt động mở chỉ số là nhỏ (theo kinh nghiệm của tôi) nhưng chi phí của GC có thể khá cao.

Trả lời

30

Trước hết chúng ta phải xác định một "viết" hoạt động. Thao tác ghi sẽ phản đối khóa khi bạn bắt đầu thao tác ghi và sẽ tiếp tục cho đến khi bạn đóng đối tượng đang thực hiện tác vụ. Chẳng hạn như tạo một IndexWriter và lập chỉ mục một tài liệu sẽ làm cho ghi để đối tượng một khóa và nó sẽ giữ khóa này cho đến khi bạn đóng IndexWriter.

Bây giờ chúng ta có thể nói về khóa một chút. Khóa này là đối tượng là khóa dựa trên tệp. Giống như mythz đã đề cập trước đó, có một tập tin gọi là 'write.lock' được tạo ra. Khi khóa ghi được phản đối, nó là độc quyền! Khóa này làm cho tất cả các hoạt động sửa đổi chỉ mục (IndexWriter và một số phương thức từ IndexReader) phải chờ cho đến khi khóa được gỡ bỏ.

Nhìn chung, bạn có nhiều lần đọc trên chỉ mục. Bạn thậm chí có thể đọc và viết cùng một lúc, không có vấn đề gì. Nhưng có một vấn đề khi có nhiều nhà văn. Nếu một sợi đang chờ khóa quá lâu, nó sẽ hết thời gian chờ.

1) Giải pháp # 1 Operations Direct

Nếu bạn chắc chắn rằng các hoạt động lập chỉ mục của bạn là ngắn và nhanh chóng, bạn có thể chỉ cần sử dụng các chỉ số tương tự cùng một lúc. Nếu không, bạn sẽ phải suy nghĩ về cách bạn muốn tổ chức các hoạt động lập chỉ mục của các ứng dụng.

2) Giải pháp # 2 Web Service

Vì bạn đang làm việc với một giải pháp web nó có thể là có thể tạo ra một dịch vụ web. Khi triển khai dịch vụ web này, tôi sẽ dành một chuỗi công nhân để lập chỉ mục. Tôi sẽ tạo ra một hàng đợi công việc để chứa công việc và nếu hàng đợi chứa nhiều công việc để làm, nó sẽ lấy tất cả chúng và làm chúng thành hàng loạt. Điều này sẽ giải quyết tất cả các vấn đề.

3) tạo ra chỉ số khác, sau đó sáp nhập

Nếu ứng dụng giao diện điều khiển không làm việc nặng về chỉ số bạn có thể nhìn vào có ứng dụng giao diện điều khiển bạn có thể tạo ra một chỉ số riêng biệt trong việc áp dụng giao diện điều khiển và sau đó hợp nhất các chỉ mục tại một số thời gian được lập lịch an toàn bằng cách sử dụng IndexWriter.AddIndexes.

từ đây bạn có thể thực hiện việc này theo hai cách, bạn có thể hợp nhất với chỉ mục trực tiếp. Hoặc bạn có thể hợp nhất để tạo chỉ mục thứ 3 và sau đó khi chỉ mục này sẵn sàng thay thế chỉ mục gốc. Bạn phải cẩn thận trong những gì bạn làm ở đây cũng như để đảm bảo rằng bạn sẽ không khóa một cái gì đó trong sử dụng nặng và gây ra một thời gian chờ cho các hoạt động viết khác.

4) Index & Tìm kiếm nhiều chỉ số

Cá nhân tôi nghĩ mọi người cần phải tách biệt các chỉ số của họ ra. Điều này giúp phân chia trách nhiệm của các chương trình và giảm thiểu thời gian xuống và duy trì việc có một điểm duy nhất cho tất cả các chỉ mục. Ví dụ: nếu ứng dụng bảng điều khiển của bạn chỉ chịu trách nhiệm cho việc thêm vào một số trường nhất định hoặc bạn đang mở rộng chỉ mục, bạn có thể xem xét các chỉ mục riêng biệt, nhưng duy trì danh tính bằng cách sử dụng trường ID trong mỗi tài liệu. Bây giờ với điều này bạn có thể tận dụng lợi thế của việc xây dựng trong hỗ trợ cho việc tìm kiếm nhiều chỉ mục bằng cách sử dụng lớp MultiSercher. Hoặc nếu bạn muốn có cũng là một lớp ParallelMultiSearch tốt đẹp có thể tìm kiếm cả hai chỉ mục cùng một lúc.

5) Nhìn vào Solr

Cái gì khác có thể giúp vấn đề của bạn duy trì một nơi duy nhất để bạn có chỉ mục, bạn có thể thay đổi chương trình của bạn để làm việc với một máy chủ Solr. http://lucene.apache.org/solr/ cũng có thư viện SOLRNET http://code.google.com/p/solrnet/ tốt đẹp có thể hữu ích trong trường hợp này. Mặc dù tôi không có kinh nghiệm với solr nhưng tôi dưới ấn tượng rằng nó sẽ giúp bạn quản lý tình hình như thế này. Ngoài ra, nó còn có các lợi ích khác như đánh dấu nhấn và tìm kiếm các mục có liên quan bằng cách tìm các mục "MoreLikeThis", hoặc cung cấp kiểm tra chính tả.

Tôi chắc chắn có nhiều phương pháp khác nhưng đây là tất cả những phương pháp mà tôi có thể nghĩ đến. Nhìn chung, giải pháp của bạn phụ thuộc vào số lượng người đang viết và cách cập nhật chỉ mục tìm kiếm bạn cần. Nhìn chung, nếu bạn có thể trì hoãn một số hoạt động cho lần sau và thực hiện một số thao tác theo lô trong mọi tình huống sẽ mang lại cho bạn hiệu suất cao nhất. Đề nghị của tôi là để hiểu những gì bạn có thể làm việc với và đi từ đó. chúc may mắn

+0

Ồ. Cảm ơn. Tôi đã suy nghĩ của một giải pháp đó là bằng cách nào đó liên quan đến 2_. Trong khi chờ đợi tôi có câu hỏi khác: "Có bao nhiêu chỉ mục có thể hỗ trợ ParallelMultiSearch hoặc MultiSercher"? –

6

Tôi cũng có một chỉ mục tìm kiếm linh hoạt được nhiều khách hàng sử dụng, tôi giải quyết vấn đề này bằng cách thực hiện 'Dịch vụ tìm kiếm Lucene' một dịch vụ web riêng biệt chạy trong Miền ứng dụng riêng của mình. Vì cả hai máy khách đều truy cập cùng một dịch vụ web để tìm kiếm hoặc cập nhật chỉ mục, tôi có thể làm cho nó an toàn với các khóa trên các chỉ mục của Lucene.

Ngoài ra nếu bạn muốn giữ nó trong quá trình tôi đề nghị sử dụng khóa tập tin để đảm bảo chỉ có một khách hàng có thể ghi vào chỉ mục.

Để sử dụng chỉ mục mới, tôi tạo một chỉ mục mới và sau đó yêu cầu dịch vụ Chỉ mục tìm kiếm hoán đổi để sử dụng chỉ mục mới bằng cách xử lý an toàn bất kỳ Trình lập chỉ mục nào trên chỉ mục hiện tại và đổi tên thư mục, ví dụ:

  • Index.Current> Index.Old
  • Index.New> Index.Current
+0

Bạn có thể rõ ràng hơn về khóa tệp không? Vì vậy, bạn đang xây dựng lại một chỉ mục mới và sau đó thực hiện chuyển đổi sang chỉ mục mới và sau đó xóa một chỉ mục cũ? Cảm ơn. –

+0

Vâng, tôi chỉ muốn tạo một tệp rỗng có tên là 'write.lock' trên hệ thống tệp để cho biết bạn đang ghi vào chỉ mục. Khi bạn viết xong chỉ mục, bạn chỉ cần xóa nó. Sau đó, bạn chỉ cần đảm bảo rằng chỉ có quá trình tạo khóa mới có thể đọc/ghi vào chỉ mục. – mythz

5

Nếu bạn sẽ có nhiều tác giả trong quá trình khác nhau, và họ sẽ chi tiêu nhiều hơn 10 giây bằng văn bản thay đổi của họ để chỉ số (mà sẽ gây ra chờ đợi nhà văn để thời gian chờ), sau đó bạn có thể đồng bộ hóa truy cập trên các quy trình bằng cách sử dụng có tên Mutexes.Chỉ cần mở/tạo một Mutex có cùng tên chung trong mỗi ứng dụng và sử dụng Mutex.WaitOne trước khi viết và Mutex.ReleaseMutex sau khi viết.

var mut = Mutex.OpenExisting("myUniqueMutexName"); // wrap in try..catch to create if non-existent 
mut.WaitOne(); 
try { 
    // write logic 
} 
finally { 
    // recover from write failure 
    mut.ReleaseMutex(); 
} 

Có lẽ tốt hơn làm cho Mutex trở thành singleton vì chúng đắt tiền để xây dựng.

Cập nhật (mỗi bình luận):

Nếu các quá trình trên máy riêng biệt, tôi nghĩ rằng lựa chọn duy nhất của bạn là lớp khóa hệ thống tập tin riêng của bạn (sử dụng file khóa kiểu cũ) để đồng bộ hóa truy cập. Vì khóa tích hợp sử dụng khóa hệ thống tệp, tôi thực sự khuyên bạn chỉ cần tăng thời gian chờ IndexWriter mỗi khi bạn xây dựng một.

var iw = new IndexWriter(); 
iw.WRITE_LOCK_TIMEOUT = 60000; 

Bạn cũng có thể tiếp tục thử một số lần được chỉ định.

var committed = false; 
var attempts = 0; 
while(!committed && attempts < 10) { 
    try { 
    // write logic 
    committed = true; 
    } catch (LockObtainFailedException) { 
    attempts++; 
    } 
} 
+0

Cảm ơn bạn đã giải pháp. Tôi sẽ là một người tốt nhưng vì cơ sở hạ tầng nó không thể được áp dụng bởi vì các tiến trình đang chạy trên các máy khác nhau và đang truy cập vào chỉ mục Lucene trong một thư mục mạng chia sẻ. Vì vậy, mutex sẽ không thể chặn các quy trình đó. –

+0

Mặc dù tôi không chỉ rõ điều này trong câu hỏi. Tôi xin lôi. –

+0

Tôi đã cập nhật câu trả lời của mình để trả lời nhận xét của bạn. –