2012-12-28 22 views
13

Tôi đang cố gắng triển khai chỉ mục tài liệu (tương ứng với hàng DB), trong đó một trong các trường là số nguyên. Tôi bổ sung chúng vào chỉ số như:Làm thế nào để tìm kiếm một trường int trong Lucene 4?

Document doc = new Document(); 
doc.add(new StringField("ticket_number", rs.getString("ticket_number"), 
     Field.Store.YES)); 
doc.add(new IntField("ticket_id", rs.getInt("ticket_id"), 
     Field.Store.YES)); 
doc.add(new StringField("id_s", rs.getString("ticket_id"), 
     Field.Store.YES)); 
w.addDocument(doc); 

Dường như tôi không thể truy vấn các lĩnh vực ticket_id ở tất cả, trong khi id_s công trình tốt.

Một trong những tài liệu là (tôi thêm khoảng trắng để có thể đọc):

Document< 
    stored,indexed,tokenized,omitNorms,indexOptions=DOCS_ONLY<ticket_number:230114W> 
    stored<ticket_id:152> 
    stored,indexed,tokenized,omitNorms,indexOptions=DOCS_ONLY<id_s:152>> 

Vì vậy, lĩnh vực int của tôi được lưu trữ, nhưng không lập chỉ mục. Truy vấn này hoạt động như mong đợi: id_s:152, trong khi truy vấn này không bao giờ trả về bất cứ điều gì: ticket_id:152.

Tôi đang làm gì sai? Làm thế nào tôi có thể thêm một trường như vậy vào chỉ mục và làm cho nó có thể tìm kiếm được?

Trả lời

7

Trường số có thể được truy vấn bằng NumericRangeQuery. Đối với đối sánh chính xác, chỉ cần đặt giá trị lớn nhất và tối thiểu bằng nhau.

Đầu ra của bạn cho biết trường không được lập chỉ mục có thể là do sự khác biệt về cách giá trị số được lập chỉ mục, so với giá trị văn bản. Xét rằng trường được chuyển thành dạng đại diện số của Lucene, giá trị theo nghĩa đen 152 thực sự sẽ không được lập chỉ mục

Tuy nhiên, có thể xử lý id_s của bạn có thể là lựa chọn tốt hơn. Các ID thường không được xử lý như các giá trị số, mà đúng hơn là các số nhận dạng đơn giản xảy ra để được biểu diễn bằng các chữ số. Nếu bạn không cần phân loại số hoặc phạm vi truy vấn trên trường, việc lập chỉ mục dưới dạng StringField chắc chắn sẽ có ý nghĩa hơn.

18

Dưới đây làm việc cho tôi:

RAMDirectory idx = new RAMDirectory(); 
    IndexWriter writer = new IndexWriter(
      idx, 
      new IndexWriterConfig(Version.LUCENE_40, new ClassicAnalyzer(Version.LUCENE_40)) 
    ); 
    Document document = new Document(); 
    document.add(new StringField("ticket_number", "t123", Field.Store.YES)); 
    document.add(new IntField("ticket_id", 234, Field.Store.YES)); 
    document.add(new StringField("id_s", "234", Field.Store.YES)); 
    writer.addDocument(document); 
    writer.commit(); 

    IndexReader reader = DirectoryReader.open(idx); 
    IndexSearcher searcher = new IndexSearcher(reader); 

    Query q1 = new TermQuery(new Term("id_s", "234")); 
    TopDocs td1 = searcher.search(q1, 1); 
    System.out.println(td1.totalHits); // prints "1" 

    Query q2 = NumericRangeQuery.newIntRange("ticket_id", 1, 234, 234, true, true); 
    TopDocs td2 = searcher.search(q2, 1); 
    System.out.println(td2.totalHits); // prints "1" 

Như femtoRgon chỉ ra, đối với các giá trị số (chờ đợi, ngày tháng, phao, vv), bạn cần phải có NumericRangeQuery và xác định chính xác. Nếu không Lucene không có ý tưởng làm thế nào để bạn muốn xác định sự giống nhau.

+0

Cảm ơn người đàn ông, điều này đã giúp tôi rất nhiều. – SoluableNonagon

+0

Liệu '234' có chỉ ra cùng một phần dữ liệu hay không, nếu vậy tôi không nghĩ rằng quyền lưu trữ nó trong chỉ mục hai lần, một lần như một chuỗi và một lần là một int. –

+0

'234' được lưu trữ với các trường khác nhau (' ticket_id' và 'id_s'). Tôi không thấy bất cứ điều gì sai trái với điều này. Về mặt khái niệm, điều này có thể sai, nhưng mục đích của ví dụ này chỉ là chứng minh cả hai kỹ thuật là có thể. – mindas

4

câu trả lời khác xuất phát từ chủ đề này (câu trả lời thứ ba): Lucene 4.0 IndexWriter updateDocument for Numeric Term

Về cơ bản, bạn tạo một hạn với giá trị int của bạn như thế này:

String field = "myfield"; 
int value = 4711; 
BytesRef bytes = new BytesRef(NumericUtils.BUF_SIZE_INT); 
NumericUtils.intToPrefixCoded(value, 0, bytes); 
Term term = new Term(field, bytes); 

Sau đó, bạn có thể sử dụng thuật ngữ này để tìm kiếm, hoặc xóa/cập nhật chỉ mục của bạn. Trong một thử nghiệm đầu tiên, điều này làm việc tốt cho tôi. Tôi không thể biết đây có phải là cách "đúng" để làm mọi thứ hay không. Tôi đã sử dụng NumericRangeFilter trước đây để lọc IntFields, nhưng bây giờ tôi có khuynh hướng sử dụng phương pháp này và sử dụng TermFilter thông thường hoặc TermQueries thay thế.

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