- Added query manager to handle various query types, which delegates to proper query engines and child factories.

- more refactoring to handle word lists.
This commit is contained in:
adam-m 2012-01-03 18:37:20 -05:00
parent 529afce917
commit c8ffe6005f
8 changed files with 394 additions and 152 deletions

View File

@ -31,7 +31,7 @@ class KeywordSearch {
private static final String BASE_URL = "http://localhost:8983/solr/";
private static final Server SERVER = new Server(BASE_URL);
public enum QueryType {LUCENE, REGEX};
public enum QueryType {WORD, REGEX};
public static final String NUM_FILES_CHANGE_EVT = "NUM_FILES_CHANGE_EVT";

View File

@ -28,6 +28,7 @@ import javax.swing.JOptionPane;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation;
/**
* Provides a data explorer to perform Solr searches with
@ -48,7 +49,7 @@ public class KeywordSearchDataExplorer implements DataExplorer {
tc.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
QueryType queryType = null;
if (tc.isLuceneQuerySelected()) {
queryType = QueryType.LUCENE;
queryType = QueryType.WORD;
} else {
queryType = QueryType.REGEX;
}
@ -78,39 +79,16 @@ public class KeywordSearchDataExplorer implements DataExplorer {
* @param solrQuery
*/
private void search(String query, QueryType queryType) {
KeywordSearchQueryManager man = new KeywordSearchQueryManager(query, queryType, Presentation.DETAIL);
switch (queryType) {
case LUCENE:
searchLuceneQuery(query);
break;
case REGEX:
searchRegexQuery(query);
break;
default:
}
}
/**
* Executes a Lucene query and populates a DataResult tab with the results
* @param solrQuery
*/
private void searchRegexQuery(String regexQuery) {
TermComponentQuery rq = new TermComponentQuery(regexQuery);
if (rq.validate()) {
rq.execute();
if (man.validate()) {
man.execute();
} else {
displayErrorDialog("Invalid RegEx query syntax: " + regexQuery);
displayErrorDialog("Invalid query syntax: " + query);
}
}
/**
* Executes a Lucene query and populates a DataResult tab with the results
* @param solrQuery
*/
private void searchLuceneQuery(String luceneQuery) {
new LuceneQuery(luceneQuery).execute();
}
@Override
public org.openide.windows.TopComponent getTopComponent() {

View File

@ -47,5 +47,17 @@ public interface KeywordSearchQuery {
*/
public void escape();
/**
* return original query string
* @return the query String supplied originally
*/
public String getQueryString();
/**
* return escaped query string if escaping was done
* @return the escaped query string, or original string if no escaping done
*/
public String getEscapedQueryString();
}

View File

@ -0,0 +1,158 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.keywordsearch;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
import org.sleuthkit.datamodel.FsContent;
/**
* Query manager responsible for running appropriate queries and displaying results
* for single, multi keyword queries, with detailed or collapsed results
*/
public class KeywordSearchQueryManager implements KeywordSearchQuery {
public enum Presentation {
COLLAPSE, DETAIL
};
//map query->boolean (true if literal, false otherwise)
private Map<String, Boolean> queries;
private Presentation presentation;
private List<KeywordSearchQuery> queryDelegates;
private QueryType queryType;
private static Logger logger = Logger.getLogger(KeywordSearchQueryManager.class.getName());
public KeywordSearchQueryManager(Map<String, Boolean> queries, Presentation presentation) {
this.queries = queries;
this.presentation = presentation;
queryType = QueryType.REGEX;
init();
}
public KeywordSearchQueryManager(String query, QueryType qt, Presentation presentation) {
queries = new LinkedHashMap<String, Boolean>();
queries.put(query, false);
this.presentation = presentation;
queryType = qt;
init();
}
public KeywordSearchQueryManager(String query, boolean isLiteral, Presentation presentation) {
queries = new LinkedHashMap<String, Boolean>();
queries.put(query, isLiteral);
this.presentation = presentation;
queryType = QueryType.REGEX;
init();
}
private void init() {
queryDelegates = new ArrayList<KeywordSearchQuery>();
for (String query : queries.keySet()) {
KeywordSearchQuery del = null;
switch (queryType) {
case WORD:
del = new LuceneQuery(query);
break;
case REGEX:
del = new TermComponentQuery(query);
break;
default:
;
}
escape();
queryDelegates.add(del);
}
}
@Override
public void execute() {
if (queryType == QueryType.WORD || presentation == Presentation.DETAIL) {
for (KeywordSearchQuery q : queryDelegates) {
q.execute();
}
} else {
for (KeywordSearchQuery q : queryDelegates) {
List<FsContent> fsContents = q.performQuery();
//TODO create view, send to proper factory
}
}
}
@Override
public void escape() {
for (KeywordSearchQuery q : queryDelegates) {
boolean shouldEscape = queries.get(q.getQueryString());
if (shouldEscape) {
q.escape();
}
}
}
@Override
public List<FsContent> performQuery() {
//not done here
return null;
}
@Override
public String getEscapedQueryString() {
StringBuilder sb = new StringBuilder();
final String SEP = queryType == QueryType.WORD ? " " : "|";
for (KeywordSearchQuery q : queryDelegates) {
sb.append(q.getEscapedQueryString()).append(SEP);
}
return sb.toString();
}
@Override
public String getQueryString() {
StringBuilder sb = new StringBuilder();
final String SEP = queryType == QueryType.WORD ? " " : "|";
for (KeywordSearchQuery q : queryDelegates) {
sb.append(q.getQueryString()).append(SEP);
}
return sb.toString();
}
@Override
public boolean validate() {
boolean allValid = true;
for (KeywordSearchQuery tcq : queryDelegates) {
if (!tcq.validate()) {
logger.log(Level.WARNING, "Query has invalid syntax: " + tcq.getQueryString());
allValid = false;
break;
}
}
return allValid;
}
}

View File

@ -20,18 +20,14 @@ package org.sleuthkit.autopsy.keywordsearch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
@ -39,22 +35,19 @@ import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode.FsContentPropertyType;
import org.sleuthkit.autopsy.datamodel.KeyValueNode;
import org.sleuthkit.autopsy.datamodel.KeyValueThing;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.File;
import org.sleuthkit.datamodel.FsContent;
/**
*
* factory responsible for assembling nodes in the right way
* factory produces top level nodes with query
* responsible for assembling nodes and columns in the right way
* and performing lazy queries as needed
*/
public class KeywordSearchResultFactory extends ChildFactory<KeyValueThing> {
public enum Presentation {
COLLAPSE, STRUCTURE
};
//common properties (superset of all Node properties) to be displayed as columns
//these are merged with FsContentPropertyType defined properties
public static enum CommonPropertyTypes {
@ -133,17 +126,66 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueThing> {
@Override
protected Node createNodeForKey(KeyValueThing thing) {
return new KeyValueNode(thing, Children.create(new RegexResultChildFactory(things), true));
ChildFactory<KeyValueThing> childFactory = null;
switch (presentation) {
case COLLAPSE:
childFactory = null;
break;
case DETAIL:
childFactory = new ResulTermsMatchesChildFactory(things);
break;
default:
}
return new KeyValueNode(thing, Children.create(childFactory, true));
}
/**
* factory produces collapsed view of all fscontent matches per query
* the node produced is a child node
* The factory actually executes query.
*/
class ResulCollapsedChildFactory extends ChildFactory<KeyValueThing> {
KeyValueThing queryThing;
ResulCollapsedChildFactory(KeyValueThing queryThing) {
this.queryThing = queryThing;
}
@Override
protected boolean createKeys(List<KeyValueThing> toPopulate) {
String origQuery = queryThing.getName();
TermComponentQuery tcq = new TermComponentQuery(origQuery);
Map<String,Object> map = new LinkedHashMap<String,Object>();
if (tcq.validate()) {
map.put("query_valid", true);
return true;
}
else {
map.put("query_valid", false);
return false;
}
//return toPopulate.addAll(things);
}
@Override
protected Node createNodeForKey(KeyValueThing thing) {
return new KeyValueNode(thing, Children.LEAF);
//return new KeyValueNode(thing, Children.create(new ResultFilesChildFactory(thing), true));
}
}
/**
* factory produces top level result nodes showing *exact* regex match result
*/
class RegexResultChildFactory extends ChildFactory<KeyValueThing> {
class ResulTermsMatchesChildFactory extends ChildFactory<KeyValueThing> {
Collection<KeyValueThing> things;
RegexResultChildFactory(Collection<KeyValueThing> things) {
ResulTermsMatchesChildFactory(Collection<KeyValueThing> things) {
this.things = things;
}
@ -155,7 +197,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueThing> {
@Override
protected Node createNodeForKey(KeyValueThing thing) {
//return new KeyValueNode(thing, Children.LEAF);
return new KeyValueNode(thing, Children.create(new RegexResultDetailsChildFactory(thing), true));
return new KeyValueNode(thing, Children.create(new ResultFilesChildFactory(thing), true));
}
/**
@ -164,11 +206,11 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueThing> {
* To implement exact regex match detail view, we need to extract files content
* returned by Lucene and further narrow down by applying a Java regex
*/
class RegexResultDetailsChildFactory extends ChildFactory<KeyValueThing> {
class ResultFilesChildFactory extends ChildFactory<KeyValueThing> {
private KeyValueThing thing;
RegexResultDetailsChildFactory(KeyValueThing thing) {
ResultFilesChildFactory(KeyValueThing thing) {
this.thing = thing;
}
@ -200,7 +242,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueThing> {
final Content content = thingContent.getContent();
final String query = thingContent.getQuery();
final String contentStr = getSolrContent(content);
final String contentStr = KeywordSearch.getServer().getCore().getSolrContent(content);
//make sure the file contains a match (this gets rid of large number of false positives)
//TODO option in GUI to include approximate matches (faster)
@ -228,19 +270,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueThing> {
}
}
private String getSolrContent(final Content content) {
final Server.Core solrCore = KeywordSearch.getServer().getCore();
final SolrQuery q = new SolrQuery();
q.setQuery("*:*");
q.addFilterQuery("id:" + content.getId());
q.setFields("content");
try {
return (String) solrCore.query(q).getResults().get(0).getFieldValue("content");
} catch (SolrServerException ex) {
logger.log(Level.WARNING, "Error getting content from Solr and validating regex match", ex);
return null;
}
}
}
/*

View File

@ -42,7 +42,6 @@ import org.sleuthkit.datamodel.SleuthkitCase;
public class LuceneQuery implements KeywordSearchQuery {
private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName());
private String query; //original unescaped query
private String queryEscaped;
private boolean isEscaped;
@ -58,8 +57,17 @@ public class LuceneQuery implements KeywordSearchQuery {
queryEscaped = KeywordSearchUtil.escapeLuceneQuery(query);
isEscaped = true;
}
@Override
public String getEscapedQueryString() {
return this.queryEscaped;
}
@Override
public String getQueryString() {
return this.query;
}
/**
* Just perform the query and return result without updating the GUI
* This utility is used in this class, can be potentially reused by other classes
@ -76,7 +84,7 @@ public class LuceneQuery implements KeywordSearchQuery {
Server.Core solrCore = KeywordSearch.getServer().getCore();
SolrQuery q = new SolrQuery();
q.setQuery(queryEscaped);
q.setRows(ROWS_PER_FETCH);
q.setFields("id");
@ -120,7 +128,7 @@ public class LuceneQuery implements KeywordSearchQuery {
public void execute() {
escape();
List<FsContent> matches = performQuery();
String pathText = "Lucene query: " + query;
Node rootNode = new KeywordSearchNode(matches, query);
Node filteredRootNode = new TableFilterNode(rootNode, true);
@ -131,6 +139,6 @@ public class LuceneQuery implements KeywordSearchQuery {
@Override
public boolean validate() {
throw new UnsupportedOperationException("Not supported yet.");
return query != null && ! query.equals("");
}
}

View File

@ -42,19 +42,22 @@ import org.apache.commons.httpclient.NoHttpResponseException;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.Content;
/**
* Handles for keeping track of a Solr server and its cores
*/
class Server {
private static final Logger logger = Logger.getLogger(Server.class.getName());
private static final String DEFAULT_CORE_NAME = "coreCase";
// TODO: DEFAULT_CORE_NAME needs to be replaced with unique names to support multiple open cases
public static final String CORE_EVT = "CORE_EVT";
public enum CORE_EVT_STATES { STOPPED, STARTED };
public static final String CORE_EVT = "CORE_EVT";
public enum CORE_EVT_STATES {
STOPPED, STARTED
};
private CommonsHttpSolrServer solrServer;
private String instanceDir;
private File solrFolder;
@ -70,22 +73,22 @@ class Server {
} catch (MalformedURLException ex) {
throw new RuntimeException(ex);
}
serverAction = new ServerAction();
solrFolder = InstalledFileLocator.getDefault().locate("solr", Server.class.getPackage().getName(), false);
instanceDir = solrFolder.getAbsolutePath() + File.separator + "solr";
}
@Override
public void finalize() throws java.lang.Throwable {
stop();
super.finalize();
}
public void addServerActionListener(PropertyChangeListener l) {
serverAction.addPropertyChangeListener(l);
}
/**
* Helper threads to handle stderr/stdout from Solr process
*/
@ -111,8 +114,7 @@ class Server {
}
}
}
/**
* Tries to start a Solr instance in a separate process. Returns immediately
* (probably before the server is ready) and doesn't check whether it was
@ -122,11 +124,11 @@ class Server {
logger.log(Level.INFO, "Starting Solr server from: " + solrFolder.getAbsolutePath());
try {
Process start = Runtime.getRuntime().exec("java -DSTOP.PORT=8079 -DSTOP.KEY=mysecret -jar start.jar", null, solrFolder);
// Handle output to prevent process from blocking
(new InputStreamPrinterThread(start.getInputStream())).start();
(new InputStreamPrinterThread(start.getErrorStream())).start();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
@ -144,15 +146,14 @@ class Server {
logger.log(Level.INFO, "Stopping Solr server from: " + solrFolder.getAbsolutePath());
Process stop = Runtime.getRuntime().exec("java -DSTOP.PORT=8079 -DSTOP.KEY=mysecret -jar start.jar --stop", null, solrFolder);
return stop.waitFor() == 0;
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
/**
* Tests if there's a Solr server running by sending it a core-status request.
* @return false if the request failed with a connection error, otherwise true
@ -165,9 +166,9 @@ class Server {
CoreAdminRequest.getStatus(null, solrServer);
} catch (SolrServerException ex) {
Throwable cause = ex.getRootCause();
// TODO: check if SocketExceptions should actually happen (is
// probably caused by starting a connection as the server finishes
// shutting down)
@ -182,11 +183,9 @@ class Server {
return true;
}
/**** Convenience methods for use while we only open one case at a time ****/
private Core currentCore = null;
void openCore() {
if (currentCore != null) {
throw new RuntimeException("Already an open Core!");
@ -194,7 +193,7 @@ class Server {
currentCore = openCore(Case.getCurrentCase());
serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STARTED);
}
void closeCore() {
if (currentCore == null) {
throw new RuntimeException("No currently open Core!");
@ -203,18 +202,15 @@ class Server {
currentCore = null;
serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STOPPED);
}
Core getCore() {
if (currentCore == null) {
throw new RuntimeException("No currently open Core!");
}
return currentCore;
}
/**** end single-case specific methods ****/
/**** end single-case specific methods ****/
/**
* Open a core for the given case
* @param c
@ -258,7 +254,6 @@ class Server {
// handle to the core in Solr
private String name;
// the server to access a core needs to be built from a URL with the
// core in it, and is only good for core-specific operations
private SolrServer solrCore;
@ -271,20 +266,33 @@ class Server {
throw new RuntimeException(ex);
}
}
Ingester getIngester() {
public Ingester getIngester() {
return new Ingester(this.solrCore);
}
QueryResponse query(SolrQuery sq) throws SolrServerException {
public QueryResponse query(SolrQuery sq) throws SolrServerException {
return solrCore.query(sq);
}
TermsResponse queryTerms(SolrQuery sq) throws SolrServerException {
public TermsResponse queryTerms(SolrQuery sq) throws SolrServerException {
QueryResponse qres = solrCore.query(sq);
return qres.getTermsResponse();
}
public String getSolrContent(final Content content) {
final SolrQuery q = new SolrQuery();
q.setQuery("*:*");
q.addFilterQuery("id:" + content.getId());
q.setFields("content");
try {
return (String) solrCore.query(q).getResults().get(0).getFieldValue("content");
} catch (SolrServerException ex) {
logger.log(Level.WARNING, "Error getting content from Solr and validating regex match", ex);
return null;
}
}
void close() {
try {
CoreAdminRequest.unloadCore(this.name, solrServer);
@ -294,7 +302,7 @@ class Server {
throw new RuntimeException(ex);
}
}
/**
* Execute query that gets only number of all Solr documents indexed
* without actually returning the documents
@ -302,17 +310,17 @@ class Server {
* @throws SolrServerException
*/
public int queryNumIndexedFiles() throws SolrServerException {
SolrQuery q = new SolrQuery("*:*");
q.setRows(0);
return (int)query(q).getResults().getNumFound();
SolrQuery q = new SolrQuery("*:*");
q.setRows(0);
return (int) query(q).getResults().getNumFound();
}
}
}
class ServerAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
logger.log(Level.INFO, e.paramString().trim());
}
}
}
}

View File

@ -24,9 +24,12 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.SwingWorker;
@ -42,6 +45,7 @@ import org.openide.nodes.Node;
import org.openide.windows.TopComponent;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.datamodel.KeyValueThing;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation;
import org.sleuthkit.datamodel.FsContent;
public class TermComponentQuery implements KeywordSearchQuery {
@ -51,31 +55,23 @@ public class TermComponentQuery implements KeywordSearchQuery {
private static final String TERMS_SEARCH_FIELD = "content_ws";
private static final String TERMS_HANDLER = "/terms";
private static final int TERMS_TIMEOUT = 90 * 1000; //in ms
private static Logger logger = Logger.getLogger(TermComponentQuery.class.getName());
private String termsQuery;
private String queryEscaped;
private boolean isEscaped;
public TermComponentQuery(String query) {
this.termsQuery = query;
this.queryEscaped = query;
isEscaped = false;
}
@Override
public void escape() {
//treat as literal
queryEscaped = Pattern.quote(termsQuery);
isEscaped = true;
//will use prefix terms component query instead of regex
//to treat the query as a word
}
@Override
public boolean validate() {
@ -90,8 +86,10 @@ public class TermComponentQuery implements KeywordSearchQuery {
return valid;
}
protected void executeQuery() {
/*
* helper method to create a Solr terms component query
*/
protected SolrQuery createQuery() {
final SolrQuery q = new SolrQuery();
q.setQueryType(TERMS_HANDLER);
q.setTerms(true);
@ -104,24 +102,90 @@ public class TermComponentQuery implements KeywordSearchQuery {
q.addTermsField(TERMS_SEARCH_FIELD);
q.setTimeAllowed(TERMS_TIMEOUT);
return q;
}
/*
* execute query and return terms
* helper method, can be called from the same or threaded query context
*/
protected List<Term> executeQuery(SolrQuery q) {
Server.Core solrCore = KeywordSearch.getServer().getCore();
List<Term> terms = null;
try {
TermsResponse tr = solrCore.queryTerms(q);
terms = tr.getTerms(TERMS_SEARCH_FIELD);
return terms;
} catch (SolrServerException ex) {
logger.log(Level.SEVERE, "Error executing the regex terms query: " + termsQuery, ex);
return null; //no need to create result view, just display error dialog
}
}
@Override
public String getEscapedQueryString() {
return this.queryEscaped;
}
@Override
public String getQueryString() {
return this.termsQuery;
}
/**
* return collapsed matches with all files for the query
* without per match breakdown
*/
@Override
public List<FsContent> performQuery() {
List<FsContent> results = new ArrayList();
final SolrQuery q = createQuery();
List<Term> terms = executeQuery(q);
//get unique match result files
Set<FsContent> uniqueMatches = new TreeSet<FsContent>();
for (Term term : terms) {
String word = term.getTerm();
LuceneQuery filesQuery = new LuceneQuery(word);
filesQuery.escape();
List<FsContent> matches = filesQuery.performQuery();
uniqueMatches.addAll(matches);
}
//filter out non-matching files
//escape regex if needed
//(if the original query was not literal, this must be)
String literalQuery = null;
if (isEscaped) {
literalQuery = this.queryEscaped;
} else {
literalQuery = Pattern.quote(this.termsQuery);
}
for (FsContent f : uniqueMatches) {
Pattern p = Pattern.compile(literalQuery, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
final String contentStr = KeywordSearch.getServer().getCore().getSolrContent(f);
Matcher m = p.matcher(contentStr);
if (m.find()) {
results.add(f);
}
}
return results;
}
@Override
public void execute() {
SolrQuery q = createQuery();
logger.log(Level.INFO, "Executing TermsComponent query: " + q.toString());
final SwingWorker worker = new TermsQueryWorker(q);
worker.execute();
}
@Override
public List<FsContent> performQuery() {
return null;
}
@Override
public void execute() {
executeQuery();
}
/**
* map Terms to generic Nodes with key/value pairs properties
@ -146,9 +210,9 @@ public class TermComponentQuery implements KeywordSearchQuery {
}
Node rootNode = null;
if (things.size() > 0) {
if (things.size() > 0) {
Children childThingNodes =
Children.create(new KeywordSearchResultFactory(termsQuery, things, KeywordSearchResultFactory.Presentation.COLLAPSE), true);
Children.create(new KeywordSearchResultFactory(termsQuery, things, Presentation.DETAIL), true);
rootNode = new AbstractNode(childThingNodes);
} else {
@ -156,17 +220,13 @@ public class TermComponentQuery implements KeywordSearchQuery {
}
final String pathText = "RegEx query";
// String pathText = "RegEx query: " + termsQuery
// String pathText = "RegEx query: " + termsQuery
//+ " Files with exact matches: " + Long.toString(totalMatches) + " (also listing approximate matches)";
TopComponent searchResultWin = DataResultTopComponent.createInstance("Keyword search", pathText, rootNode, things.size());
searchResultWin.requestActive(); // make it the active top component
}
class TermsQueryWorker extends SwingWorker<List<Term>, Void> {
@ -183,17 +243,7 @@ public class TermComponentQuery implements KeywordSearchQuery {
progress.start();
progress.progress("Running Terms query.");
Server.Core solrCore = KeywordSearch.getServer().getCore();
List<Term> terms = null;
try {
TermsResponse tr = solrCore.queryTerms(q);
terms = tr.getTerms(TERMS_SEARCH_FIELD);
} catch (SolrServerException ex) {
logger.log(Level.SEVERE, "Error executing the regex terms query: " + termsQuery, ex);
return null; //no need to create result view, just display error dialog
}
List<Term> terms = executeQuery(q);
progress.progress("Terms query completed.");
@ -223,8 +273,6 @@ public class TermComponentQuery implements KeywordSearchQuery {
progress.finish();
}
}
}
}
}