xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/search/DirectoryExtraReader.java (revision 9368fcecb2b7ea70174f734141303ebf227f2737)
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