2011-03-19 21 views
11

का उपयोग कर स्वत: पूर्ण मेरी वेबसाइट के लिए एक बेहतर स्वत: पूर्ण सुविधा बनाने की कोशिश कर रहा हूं। मैं इसके लिए हाइबरनेट खोज का उपयोग करना चाहता हूं लेकिन जहां तक ​​मैंने प्रयोग किया है, यह केवल मेरे लिए पूर्ण शब्द पाता है।हाइबरनेट खोज

तो, मेरा प्रश्न: क्या केवल कुछ पात्रों को खोजना संभव है?

उदाहरण के लिए। उपयोगकर्ता 3 अक्षरों को टाइप करता है और हाइबरनेट खोज का उपयोग करके उसे मेरे डीबी ऑब्जेक्ट्स के सभी शब्द दिखाता है जिसमें 3 अक्षर होते हैं?

पीएस। अभी मैं इसके लिए "पसंद" क्वेरी का उपयोग कर रहा हूं ... लेकिन मेरा डीबी बहुत बड़ा हो गया है और मैं भी अन्य टेबल पर खोज कार्यक्षमता का विस्तार करना चाहता हूं ...

उत्तर

6

आप सुझाए गए NGramFilter का उपयोग करके फ़ील्ड को इंडेक्स कर सकते हैं here। सर्वोत्तम परिणामों के लिए आपको अपाचे सोलर से EdgeNgramFilter का उपयोग करना चाहिए जो एक शब्द के शुरुआती किनारे से ngrams बनाता है और हाइबरनेट खोज में भी इसका उपयोग किया जा सकता है।

11

मेजर संपादित और मैं मूल कोड में सुधार करने में सक्षम था पर एक साल मैं इस निर्माण करने के लिए तैनात:

मेरे अनुक्रमित इकाई:

@Entity 
@Indexed 
@AnalyzerDef(name = "myanalyzer", 
// Split input into tokens according to tokenizer 
tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class), // 
filters = { // 
// Normalize token text to lowercase, as the user is unlikely to care about casing when searching for matches 
@TokenFilterDef(factory = LowerCaseFilterFactory.class), 
// Index partial words starting at the front, so we can provide Autocomplete functionality 
@TokenFilterDef(factory = NGramFilterFactory.class, params = { @Parameter(name = "maxGramSize", value = "1024") }), 
// Close filters & Analyzerdef 
}) 
@Analyzer(definition = "myanalyzer") 
public class Compound extends DomainObject { 
public static String[] getSearchFields(){...} 
... 
} 

सभी @Field रों tokenized कर रहे हैं और सूचकांक में संग्रहीत; काम करने के लिए इस के लिए आवश्यक:
@Field(index = Index.TOKENIZED, store = Store.YES)

@Transactional(readOnly = true) 
public synchronized List<String> getSuggestions(final String searchTerm) { 
    // Compose query for term over all fields in Compound 
    String lowerCasedSearchTerm = searchTerm.toLowerCase(); 

    // Create a fullTextSession for the sessionFactory.getCurrentSession() 
    FullTextSession fullTextSession = Search.getFullTextSession(getSession()); 

    // New DSL based query composition 
    SearchFactory searchFactory = fullTextSession.getSearchFactory(); 
    QueryBuilder buildQuery = searchFactory.buildQueryBuilder().forEntity(Compound.class).get(); 
    TermContext keyword = buildQuery.keyword(); 
    WildcardContext wildcard = keyword.wildcard(); 
    String[] searchfields = Compound.getSearchfields(); 
    TermMatchingContext onFields = wildcard.onField(searchfields[0]); 
    for (int i = 1; i < searchfields.length; i++) 
     onFields.andField(searchfields[i]); 
    TermTermination matching = onFields.matching(input.toLowerCase()); 
    Query query = matching.createQuery(); 

    // Convert the Search Query into something that provides results: Specify Compound again to be future proof 
    FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query, Compound.class); 
    fullTextQuery.setMaxResults(20); 

    // Projection does not work on collections or maps which are indexed via @IndexedEmbedded 
    List<String> projectedFields = new ArrayList<String>(); 
    projectedFields.add(ProjectionConstants.DOCUMENT); 
    List<String> embeddedFields = new ArrayList<String>(); 
    for (String fieldName : searchfields) 
     if (fieldName.contains(".")) 
      embeddedFields.add(fieldName); 
     else 
      projectedFields.add(fieldName); 

    @SuppressWarnings("unchecked") 
    List<Object[]> results = fullTextQuery.setProjection(projectedFields.toArray(new String[projectedFields.size()])).list(); 

    // Keep a list of suggestions retrieved by search over all fields 
    List<String> suggestions = new ArrayList<String>(); 
    for (Object[] projectedObjects : results) { 
     // Retrieve the search suggestions for the simple projected field values 
     for (int i = 1; i < projectedObjects.length; i++) { 
      String fieldValue = projectedObjects[i].toString(); 
      if (fieldValue.toLowerCase().contains(lowerCasedSearchTerm)) 
       suggestions.add(fieldValue); 
     } 

     // Extract the search suggestions for the embedded fields from the document 
     Document document = (Document) projectedObjects[0]; 
     for (String fieldName : embeddedFields) 
      for (Field field : document.getFields(fieldName)) 
       if (field.stringValue().toLowerCase().contains(lowerCasedSearchTerm)) 
        suggestions.add(field.stringValue()); 
    } 

    // Return the composed list of suggestions, which might be empty 
    return suggestions; 
} 

कुछ खींचतान मैं अंत @IndexedEmbedded क्षेत्रों को संभालने के लिए पर कर रहा हूँ नहीं है। यदि आपके पास नहीं है तो आप केवल कोडफिल्ड्स को प्रोजेक्ट करने के लिए कोड को सरल बना सकते हैं, और & एम्बेडेड फ़ील्ड हैंडलिंग को छोड़कर दस्तावेज़ को सरल बना सकते हैं।

पहले की तरह: उम्मीद है कि इस प्रश्न का सामना करने के लिए अगले व्यक्ति के लिए यह उपयोगी है। अगर किसी को उपरोक्त पोस्ट कोड में कोई आलोचना या सुधार हो, तो इसे संपादित करने के लिए स्वतंत्र महसूस करें और कृपया मुझे बताएं।


Edit3: परियोजना के लिए इस कोड से लिया गया है के बाद से खुला का पता चला है; यहाँ प्रासंगिक वर्ग हैं:

https://trac.nbic.nl/metidb/browser/trunk/metidb/metidb-core/src/main/java/org/metidb/domain/Compound.java
https://trac.nbic.nl/metidb/browser/trunk/metidb/metidb-core/src/main/java/org/metidb/dao/CompoundDAOImpl.java
https://trac.nbic.nl/metidb/browser/trunk/metidb/metidb-search/src/main/java/org/metidb/search/text/Autocompleter.java

+0

एक और मुद्दा यह है कि परिणाम केवल एक शब्द के लिए दिखाई देते हैं यदि मैं उदाहरण के लिए खोज करता हूं: "मस्तिष्क" परिणाम होता है लेकिन "मस्तिष्क" के लिए कोई नहीं होता है। क्या इसे संभालने का कोई तरीका है? – nanospeck

+0

टर्म टर्मिनेशन मिलान = onFields.matching (input.toLowerCase()); मुझे यह भी लगता है कि 'input.toLowerCase()' को 'lowCasedSearchTerm' होना चाहिए था। – nanospeck

+0

@nanospeck मैं थोड़ी अस्पष्ट हूं क्योंकि यह थोड़ी देर के बाद से मैंने इस पर काम किया है, लेकिन वाक्यांश की खोज के बारे में "मस्तिष्क" आपको कुछ और चीज़ों के लिए 'व्हाइटस्पेस टोकेनाइज़र फैक्टरी' को समायोजित करना पड़ सकता है, क्योंकि मुझे लगता है कि चॉप अप व्यक्तिगत शब्द – Tim

2

टिम जवाब शानदार है और मुझे कठिन हिस्सा खत्म होने में मदद की। यह केवल मेरे लिए एक शब्द पूछताछ के लिए काम किया। अगर कोई इसे वाक्यांश खोजों के लिए काम करना चाहता है। बस अपने 'वाक्यांश' वर्गों के साथ सभी 'टर्म' उदाहरणों को प्रतिस्थापित करें। टिम के कोड के लिए प्रतिस्थापन लाइनें यहां दी गई हैं जो मेरे लिए चाल थीं।

// New DSL based query composition 
      //org.hibernate.search.query.dsl 
      SearchFactory searchFactory = fullTextSession.getSearchFactory(); 
      QueryBuilder buildQuery = searchFactory.buildQueryBuilder().forEntity(MasterDiagnosis.class).get(); 
      PhraseContext keyword = buildQuery.phrase(); 
      keyword.withSlop(3); 
      //WildcardContext wildcard = keyword.wildcard(); 
      String[] searchfields = MasterDiagnosis.getSearchfields(); 
      PhraseMatchingContext onFields = keyword.onField(searchfields[0]); 
      for (int i = 1; i < searchfields.length; i++) 
       onFields.andField(searchfields[i]); 
      PhraseTermination matching = onFields.sentence(lowerCasedSearchTerm); 
      Query query = matching.createQuery(); 
// Convert the Search Query into something that provides results: Specify Compound again to be future proof