1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * See LICENSE.txt included in this distribution for the specific 9 * language governing permissions and limitations under the License. 10 * 11 * When distributing Covered Code, include this CDDL HEADER in each 12 * file and include the License file at LICENSE.txt. 13 * If applicable, add the following below this CDDL HEADER, with the 14 * fields enclosed by brackets "[]" replaced with your own identifying 15 * information: Portions Copyright [yyyy] [name of copyright owner] 16 * 17 * CDDL HEADER END 18 */ 19 20 /* 21 * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. 22 * Copyright (c) 2017, 2020, Chris Fraire <cfraire@me.com>. 23 */ 24 package org.opengrok.indexer.search; 25 26 import java.io.IOException; 27 import java.util.ArrayList; 28 import java.util.List; 29 import java.util.logging.Level; 30 import java.util.logging.Logger; 31 import org.apache.lucene.document.Document; 32 import org.apache.lucene.queryparser.classic.ParseException; 33 import org.apache.lucene.search.IndexSearcher; 34 import org.apache.lucene.search.Query; 35 import org.apache.lucene.search.ScoreDoc; 36 import org.apache.lucene.search.TopDocs; 37 import org.opengrok.indexer.analysis.NullableNumLinesLOC; 38 import org.opengrok.indexer.index.NumLinesLOCUtil; 39 import org.opengrok.indexer.logger.LoggerFactory; 40 import org.opengrok.indexer.util.Statistics; 41 42 /** 43 * Represents a searcher to supplement metadata from the file-system with 44 * per-file, OpenGrok-analyzed data. 45 */ 46 public class DirectoryExtraReader { 47 48 // N.b.: update #search() comment when changing 49 private static final int DIR_LIMIT_NUM = 2000; 50 51 private static final Logger LOGGER = LoggerFactory.getLogger( 52 DirectoryExtraReader.class); 53 54 /** 55 * Search for supplemental file information in the specified {@code path}. 56 * @param searcher a defined instance 57 * @param path a defined path to qualify the search 58 * @return a list of results, limited to 2000 values 59 * @throws IOException if an error occurs searching the index 60 */ search(IndexSearcher searcher, String path)61 public List<NullableNumLinesLOC> search(IndexSearcher searcher, String path) 62 throws IOException { 63 if (searcher == null) { 64 throw new IllegalArgumentException("`searcher' is null"); 65 } 66 if (path == null) { 67 throw new IllegalArgumentException("`path' is null"); 68 } 69 70 QueryBuilder qbuild = new QueryBuilder(); 71 qbuild.setDirPath(path); 72 Query query; 73 try { 74 query = qbuild.build(); 75 } catch (ParseException e) { 76 final String PARSE_ERROR = 77 "An error occurred while parsing dirpath query"; 78 LOGGER.log(Level.WARNING, PARSE_ERROR, e); 79 throw new IOException(PARSE_ERROR); 80 } 81 82 Statistics stat = new Statistics(); 83 TopDocs hits = searcher.search(query, DIR_LIMIT_NUM); 84 85 stat.report(LOGGER, Level.FINEST, "search via DirectoryExtraReader done", 86 "search.latency", new String[]{"category", "extra", 87 "outcome", hits.scoreDocs.length > 0 ? "success" : "empty"}); 88 89 List<NullableNumLinesLOC> results = processHits(searcher, hits); 90 91 return results; 92 } 93 processHits(IndexSearcher searcher, TopDocs hits)94 private List<NullableNumLinesLOC> processHits(IndexSearcher searcher, TopDocs hits) 95 throws IOException { 96 97 List<NullableNumLinesLOC> results = new ArrayList<>(); 98 99 for (ScoreDoc sd : hits.scoreDocs) { 100 Document d = searcher.doc(sd.doc); 101 NullableNumLinesLOC extra = NumLinesLOCUtil.read(d); 102 results.add(extra); 103 } 104 105 return results; 106 } 107 } 108