2010-03-17 46 views
8

Tôi muốn triển khai chức năng tìm kiếm trong ứng dụng viết blog django. Hiện trạng là tôi có một danh sách các chuỗi được cung cấp bởi người dùng và bộ truy vấn được thu hẹp bởi mỗi chuỗi để chỉ bao gồm các đối tượng khớp với chuỗi đó.Làm thế nào để thực hiện tìm kiếm toàn văn trong Django?

Xem:

if request.method == "POST": 
    form = SearchForm(request.POST) 
    if form.is_valid(): 
     posts = Post.objects.all() 
     for string in form.cleaned_data['query'].split(): 
      posts = posts.filter(
        Q(title__icontains=string) | 
        Q(text__icontains=string) | 
        Q(tags__name__exact=string) 
        ) 
     return archive_index(request, queryset=posts, date_field='date') 

Bây giờ, những gì nếu tôi không muốn làm tiếp nhau mỗi từ được tìm kiếm bởi một logic AND nhưng với một logic OR? Tôi sẽ làm như thế nào? Có cách nào để làm điều đó với phương pháp Queryset riêng của Django hay không phải là một trong những để trở lại truy vấn SQL nguyên?

Nói chung, đây có phải là giải pháp thích hợp để thực hiện tìm kiếm văn bản đầy đủ như thế này hay bạn khuyên bạn nên sử dụng công cụ tìm kiếm như Solr, Whoosh hoặc Xapian. Lợi ích của chúng là gì?

Trả lời

15

Tôi khuyên bạn nên áp dụng công cụ tìm kiếm.

Chúng tôi đã sử dụng Haystack search, một ứng dụng tìm kiếm mô-đun cho django hỗ trợ nhiều công cụ tìm kiếm (Solr, Xapian bất ngờ tới thăm, vv ...)

Ưu điểm:

  • nhanh hơn
  • thực hiện tìm kiếm truy vấn ngay cả khi không truy vấn cơ sở dữ liệu.
  • Highlight đã tìm kiếm thuật ngữ
  • "Nhiều như thế này" chức năng
  • gợi ý chính tả
  • Better xếp hạng
  • vv ...

Nhược điểm:

  • Search Indexes có thể phát triển có kích thước khá nhanh
  • Một trong những công cụ tìm kiếm tốt nhất (Solr) chạy dưới dạng Java servlet (Xapian không)

Chúng tôi rất vui vì giải pháp này và nó khá dễ thực hiện.

2

Để tìm kiếm toàn văn bản bằng Python, hãy xem PyLucene. Nó cho phép truy vấn rất phức tạp. Vấn đề chính ở đây là bạn phải tìm cách để báo cho công cụ tìm kiếm của bạn biết các trang nào đã thay đổi và cập nhật chỉ mục cuối cùng.

Hoặc, bạn có thể sử dụng Google Sitemaps để yêu cầu Google lập chỉ mục trang web của bạn nhanh hơn và sau đó nhúng trường truy vấn tùy chỉnh vào trang web của bạn. Lợi thế ở đây là bạn chỉ cần nói cho Google biết các trang đã thay đổi và Google sẽ làm tất cả công việc khó khăn (lập chỉ mục, phân tích các truy vấn, v.v.). Trên hết, hầu hết mọi người được sử dụng để sử dụng Google để tìm kiếm cộng với nó sẽ giữ cho trang web của bạn hiện tại trong các tìm kiếm toàn cầu của Google.

5

Thực tế, truy vấn bạn đã đăng hiện sử dụng OR thay vì VÀ - bạn đang sử dụng \ để tách các đối tượng Q. VÀ sẽ là &.

Nói chung, tôi khuyên bạn nên sử dụng công cụ tìm kiếm phù hợp. Chúng tôi đã có thành công tốt với Haystack trên đầu trang của Solr - Haystack quản lý tất cả các cấu hình Solr, và cho thấy một API tốt đẹp rất giống với ORM của Django.

+0

Anh ấy nên sử dụng HOẶC nếu anh ấy muốn tìm kiếm toàn văn. Mã của anh ấy rõ ràng, nhưng mô tả hơi khó hiểu. –

+0

Nhưng các câu lệnh .filter() được AND cùng nhau, phải không? Vì vậy, mỗi đối số tìm kiếm (từ) được tìm kiếm trong tiêu đề của bài HOẶC nội dung HOẶC trong các thẻ có liên quan. Nhưng để hiển thị kết quả, một bài đăng cần phải có tất cả các đối số tìm kiếm trong tiêu đề HOẶC nội dung hoặc thẻ của nó. Điều đó tốt và chính xác những gì tôi muốn đạt được. Tôi chỉ tò mò về cách để thực hiện một kết quả chỉ cần một trong những từ được trình bày trong một trong các thuộc tính của họ (không phải tất cả chúng). – jnns

4

Trả lời câu hỏi chung: Chắc chắn sử dụng ứng dụng thích hợp cho việc này.

Với truy vấn của bạn, bạn luôn kiểm tra toàn bộ nội dung của các trường (tiêu đề, văn bản, thẻ). Bạn không được hưởng lợi từ chỉ mục, v.v.

Với công cụ tìm kiếm văn bản đầy đủ thích hợp (hoặc bất kỳ công cụ tìm kiếm nào), văn bản (từ) được lập chỉ mục mỗi khi bạn chèn bản ghi mới. Vì vậy, các truy vấn sẽ nhanh hơn rất nhiều, đặc biệt là khi cơ sở dữ liệu của bạn phát triển.

4

SOLR rất dễ cài đặt và tích hợp với Django. Haystack làm cho nó thậm chí còn đơn giản hơn.

2

Tôi nghĩ tìm kiếm văn bản đầy đủ ở cấp ứng dụng là vấn đề bạn có và cách bạn mong đợi nó mở rộng. Nếu bạn chạy một trang web nhỏ với mức sử dụng thấp, tôi nghĩ rằng nó có thể là giá cả phải chăng hơn để dành thời gian vào việc thực hiện tìm kiếm văn bản đầy đủ tùy chỉnh thay vì cài đặt một ứng dụng để thực hiện tìm kiếm cho bạn. Và ứng dụng sẽ tạo thêm sự phụ thuộc, bảo trì và nỗ lực thêm khi lưu trữ dữ liệu. Bằng cách tự tìm kiếm và bạn có thể xây dựng các tính năng tùy chỉnh đẹp mắt. Ví dụ: nếu văn bản của bạn khớp chính xác với một tiêu đề, bạn có thể hướng người dùng đến trang đó thay vì hiển thị kết quả. Một cách khác là cho phép tiêu đề: hoặc tác giả: tiền tố cho từ khóa.

Đây là phương pháp tôi đã sử dụng để tạo kết quả tìm kiếm có liên quan từ truy vấn web.

import shlex 

class WeightedGroup: 
    def __init__(self): 
     # using a dictionary will make the results not paginate 
     # but it will be a lot faster when storing data   
     self.data = {} 

    def list(self, max_len=0): 
     # returns a sorted list of the items with heaviest weight first 
     res = [] 
     while len(self.data) != 0: 
      nominated_weight = 0      
      for item, weight in self.data.iteritems(): 
       if weight > nominated_weight: 
        nominated = item 
        nominated_weight = weight 
      self.data.pop(nominated) 
      res.append(nominated) 
      if len(res) == max_len: 
       return res 
     return res 

    def append(self, weight, item): 
     if item in self.data: 
      self.data[item] += weight 
     else: 
      self.data[item] = weight 


def search(searchtext): 
    candidates = WeightedGroup() 

    for arg in shlex.split(searchtext): # shlex understand quotes 

     # Search TITLE 
     # order by date so we get most recent posts 
     query = Post.objects.filter_by(title__icontains=arg).order_by('-date') 
     arg_hits = query.count() # count is cheap 

     if arg_hits > 1000: 
      continue # skip keywords which has too many hits 

     # Each of these are expensive as it would transfer data 
     # from the db and build a python object, 
     for post in query[:50]: # so we limit it to 50 for example     
      # more hits a keyword has the lesser it's relevant 
      candidates.append(100.0/arg_hits, post.post_id) 

     # TODO add searchs for other areas 
     # Weight might also be adjusted with number of hits within the text 
     # or perhaps you can find other metrics to value an post higher, 
     # like number of views 

    # candidates can contain a lot of stuff now, show most relevant only 
    sorted_result = Post.objects.filter_by(post_id__in=candidates.list(20)) 
Các vấn đề liên quan