1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package ensemble.search; 33 34 import ensemble.generated.Samples; 35 import java.io.BufferedReader; 36 import java.io.IOException; 37 import java.io.InputStreamReader; 38 import java.util.*; 39 import javafx.application.ConditionalFeature; 40 import javafx.application.Platform; 41 import org.apache.lucene.analysis.Analyzer; 42 import org.apache.lucene.analysis.standard.StandardAnalyzer; 43 import org.apache.lucene.document.Document; 44 import org.apache.lucene.queryParser.MultiFieldQueryParser; 45 import org.apache.lucene.queryParser.ParseException; 46 import org.apache.lucene.search.Query; 47 import org.apache.lucene.search.ScoreDoc; 48 import org.apache.lucene.search.Sort; 49 import org.apache.lucene.search.grouping.GroupDocs; 50 import org.apache.lucene.search.grouping.SearchGroup; 51 import org.apache.lucene.search.grouping.SecondPassGroupingCollector; 52 import org.apache.lucene.search.grouping.TopGroups; 53 import org.apache.lucene.util.Version; 54 55 /** 56 * Class for searching the index 57 */ 58 public class IndexSearcher { 59 private final static List<SearchGroup> searchGroups = new ArrayList<>(); 60 static { 61 for (DocumentType dt: DocumentType.values()){ 62 SearchGroup searchGroup = new SearchGroup(); 63 searchGroup.groupValue = dt.toString(); 64 searchGroup.sortValues = new Comparable[]{5f}; 65 searchGroups.add(searchGroup); 66 } 67 } 68 private org.apache.lucene.search.IndexSearcher searcher; 69 private final Analyzer analyzer; 70 private final MultiFieldQueryParser parser; 71 72 public IndexSearcher() { 73 try { 74 searcher = new org.apache.lucene.search.IndexSearcher(new ClasspathDirectory()); 75 } catch (IOException e) { 76 e.printStackTrace(); 77 } 78 analyzer = new StandardAnalyzer(Version.LUCENE_31); 79 parser = new MultiFieldQueryParser(Version.LUCENE_31, new String[]{"name","bookTitle","chapter","description"}, analyzer); 80 } 81 82 public Map<DocumentType, List<SearchResult>> search(String searchString) throws ParseException { 83 Map<DocumentType, List<SearchResult>> resultMap = new EnumMap<>(DocumentType.class); 84 try { 85 Query query = parser.parse(searchString); 86 final SecondPassGroupingCollector collector = new SecondPassGroupingCollector("documentType", searchGroups, 87 Sort.RELEVANCE, Sort.RELEVANCE, 10, true, false, true); 88 searcher.search(query, collector); 89 final TopGroups groups = collector.getTopGroups(0); 90 for (GroupDocs groupDocs : groups.groups) { 91 DocumentType docType = DocumentType.valueOf(groupDocs.groupValue); 92 List<SearchResult> results = new ArrayList<>(); 93 for (ScoreDoc scoreDoc : groupDocs.scoreDocs) { 94 if ((Platform.isSupported(ConditionalFeature.WEB)) || (docType != DocumentType.DOC)) { 95 Document doc = searcher.doc(scoreDoc.doc); 96 SearchResult result = new SearchResult( 97 docType, 98 doc.get("name"), 99 doc.get("url"), 100 doc.get("className"), 101 doc.get("package"), 102 doc.get("ensemblePath"), 103 docType == DocumentType.DOC 104 ? doc.get("bookTitle") == null ? doc.get("chapter") : doc.get("bookTitle") 105 : doc.get("shortDescription").trim() 106 ); 107 /* If the result is a sample, then filter out the samples that 108 * the runtime platform does not support. We really want to show 109 * just 5 results, but we search for 10 and filter out unsupported 110 * samples and show just 5. 111 */ 112 if (docType == DocumentType.SAMPLE) { 113 if (Samples.ROOT.sampleForPath(result.getEnsemblePath().substring(9).trim()) == null) { 114 115 // Skip unsupported (not existing) samples 116 continue; 117 } 118 if (results.size() == 5) { 119 120 // 5 samples is enough 121 break; 122 } 123 } 124 results.add(result); 125 } 126 } 127 resultMap.put(docType, results); 128 } 129 } catch (IOException e) { 130 e.printStackTrace(); 131 } 132 return resultMap; 133 } 134 135 /** 136 * Simple command line test application 137 * @param args command line arguments 138 * @throws Exception for maps errors 139 */ 140 public static void main(String[] args) throws Exception { 141 BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); 142 IndexSearcher indexSearcher = new IndexSearcher(); 143 while (true) { 144 System.out.println("Enter query: "); 145 String line = in.readLine(); 146 if (line == null || line.length() == -1) break; 147 line = line.trim(); 148 if (line.length() == 0) break; 149 Map<DocumentType, List<SearchResult>> results = indexSearcher.search(line); 150 for (Map.Entry<DocumentType, List<SearchResult>> entry : results.entrySet()) { 151 System.out.println("--------- "+entry.getKey()+" ["+entry.getValue().size()+"] --------------------------------"); 152 for(SearchResult result: entry.getValue()) { 153 System.out.println(result.toString()); 154 } 155 } 156 } 157 } 158 }