/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.getopt.luke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.zip.GZIPOutputStream;
import javax.swing.JFileChooser;
import javax.swing.UIManager;
import org.apache.lucene.LucenePackage;
import org.apache.lucene.analysis.*;
import org.apache.lucene.analysis.core.SimpleAnalyzer;
import org.apache.lucene.analysis.core.StopAnalyzer;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.analysis.payloads.PayloadHelper;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.*;
import org.apache.lucene.index.CheckIndex.Status.SegmentInfoStatus;
import org.apache.lucene.index.FieldInfo.IndexOptions;
import org.apache.lucene.index.TermsEnum.SeekStatus;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.misc.SweetSpotSimilarity;
import org.apache.lucene.queries.mlt.MoreLikeThis;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.payloads.PayloadNearQuery;
import org.apache.lucene.search.payloads.PayloadTermQuery;
import org.apache.lucene.search.similarities.DefaultSimilarity;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.search.similarities.TFIDFSimilarity;
import org.apache.lucene.search.spans.SpanFirstQuery;
import org.apache.lucene.search.spans.SpanNearQuery;
import org.apache.lucene.search.spans.SpanNotQuery;
import org.apache.lucene.search.spans.SpanOrQuery;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.lucene.store.*;
import org.apache.lucene.util.AttributeSource;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.Version;
import org.apache.lucene.util.automaton.Automaton;
import org.apache.lucene.util.automaton.Transition;
import org.apache.lucene.queryparser.xml.CoreParser;
import org.apache.lucene.queryparser.xml.CorePlusExtensionsParser;
import org.getopt.luke.DocReconstructor.Reconstructed;
import org.getopt.luke.decoders.BinaryDecoder;
import org.getopt.luke.decoders.DateDecoder;
import org.getopt.luke.decoders.Decoder;
import org.getopt.luke.decoders.NumIntDecoder;
import org.getopt.luke.decoders.NumLongDecoder;
import org.getopt.luke.decoders.SolrDecoder;
import org.getopt.luke.decoders.StringDecoder;
import org.getopt.luke.plugins.ScriptingPlugin;
import org.getopt.luke.xmlQuery.XmlQueryParserFactory;
import org.getopt.luke.xmlQuery.CorePlusExtensionsParserFactory;
import thinlet.FrameLauncher;
import thinlet.Thinlet;
/**
* This class allows you to browse a <a href="jakarta.apache.org/lucene">Lucene
* </a> index in several ways - by document, by term, by query, and by most
* frequent terms.
*
* @author Andrzej Bialecki
*
*/
public class Luke extends Thinlet implements ClipboardOwner {
private static final long serialVersionUID = -470469999079073156L;
public static Version LV = Version.LATEST;
private Directory dir = null;
String pName = null;
private IndexReader ir = null;
private AtomicReader ar = null;
private IndexSearcher is = null;
private boolean slowAccess = false;
private List<String> fn = null;
private String[] idxFields = null;
private FieldInfos infos = null;
private IndexInfo idxInfo = null;
private Map<String, FieldTermCount> termCounts;
private List<LukePlugin> plugins = new ArrayList<LukePlugin>();
private Object errorDlg = null;
private Object infoDlg = null;
private Object statmsg = null;
private Object slowstatus = null;
private Object slowmsg = null;
private Analyzer stdAnalyzer = new StandardAnalyzer();
//private QueryParser qp = null;
private boolean readOnly = false;
private boolean ram = false;
private boolean keepCommits = false;
private boolean multi = false;
private int tiiDiv = 1;
private IndexCommit currentCommit = null;
private Similarity similarity = null;
private Object lastST;
private HashMap<String, Decoder> decoders = new HashMap<String, Decoder>();
private Decoder defDecoder = new StringDecoder();
/** Default salmon theme. */
public static final int THEME_DEFAULT = 0;
/** Gray theme. */
public static final int THEME_GRAY = 1;
/** Sandstone theme. */
public static final int THEME_SANDSTONE = 2;
/** Sky blue theme. */
public static final int THEME_SKY = 3;
/** Navy blue reverse theme. */
public static final int THEME_NAVY = 4;
/** Theme color constants. */
public int[][] themes = {
{0xece9d0, 0x000000, 0xf5f4f0, 0x919b9a, 0xb0b0b0, 0xeeeeee, 0xb9b9b9, 0xff8080, 0xc5c5dd}, // default
{0xe6e6e6, 0x000000, 0xffffff, 0x909090, 0xb0b0b0, 0xededed, 0xb9b9b9, 0x89899a, 0xc5c5dd}, // gray
{0xeeeecc, 0x000000, 0xffffff, 0x999966, 0xb0b096, 0xededcb, 0xcccc99, 0xcc6600, 0xffcc66}, // sandstone
{0xf0f0ff, 0x0000a0, 0xffffff, 0x8080ff, 0xb0b0b0, 0xededed, 0xb0b0ff, 0xff0000, 0xfde0e0}, // sky
{0x6375d6, 0xffffff, 0x7f8fdd, 0xd6dff5, 0x9caae5, 0x666666, 0x003399, 0xff3333, 0x666666} // navy
};
private int numTerms = 0;
private static boolean exitOnDestroy = false;
private Class[] analyzers = null;
private String baseDir = null;
private Class[] defaultAnalyzers = { SimpleAnalyzer.class, StandardAnalyzer.class, StopAnalyzer.class,
WhitespaceAnalyzer.class };
private static final String MSG_NOINDEX = "FAILED: No index, or index is closed. Reopen it.";
private static final String MSG_READONLY = "FAILED: Read-Only index.";
private static final String MSG_EMPTY_INDEX = "Index is empty.";
private static final String MSG_CONV_ERROR = "Some values could not be properly represented in this format. " +
"They are marked in grey and presented as a hex dump.";
private static final String MSG_LUCENE3828 = "Sorry. This functionality doesn't work with Lucene trunk. See LUCENE-3828 for more details.";
/** Default constructor, loads preferences, initializes plugins and GUI. */
public Luke() {
super();
Prefs.load();
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {}
setTheme(Prefs.getInteger(Prefs.P_THEME, THEME_DEFAULT));
String fontName = Prefs.getProperty(Prefs.P_FONT_NAME, "SansSerif");
String fontSize = Prefs.getProperty(Prefs.P_FONT_SIZE, "12.0");
float fsize = 12.0f;
try {
fsize = Float.parseFloat(fontSize);
} catch (Exception e) {};
Font f = new Font(fontName, Font.PLAIN, (int)fsize);
setFont(f);
addComponent(this, "/xml/luke.xml", null, null);
errorDlg = addComponent(null, "/xml/error.xml", null, null);
infoDlg = addComponent(null, "/xml/info.xml", null, null);
statmsg = find("statmsg");
slowstatus = find("slowstat");
slowmsg = find(slowstatus, "slowmsg");
// populate analyzers
try {
Class[] an = ClassFinder.getInstantiableSubclasses(Analyzer.class);
if (an == null || an.length == 0) {
System.err.println("No analyzers???");
analyzers = defaultAnalyzers;
} else {
analyzers = an;
}
Object cbType = find("cbType");
populateAnalyzers(cbType);
} catch (Exception e) {
e.printStackTrace();
}
initSolrTypes();
loadPlugins();
}
private void initSolrTypes() {
// add Solr field decoders
String[] solrTypes = SolrDecoder.getTypes();
Object cbDec = find("cbDec");
Font f = getFont(cbDec, "font");
for (String s : solrTypes) {
Object choice = create("choice");
setFont(choice, f);
setString(choice, "name", s);
setString(choice, "text", s);
add(cbDec, choice);
}
}
/**
* Set color theme for the UI.
* @param which one of the predefined themes. For custom themes use {@link Thinlet#setColors(int, int, int, int, int, int, int, int, int)}.
*/
public void setTheme(int which) {
if (which < 0 || which >= themes.length) which = THEME_DEFAULT;
int[] t = themes[which];
setColors(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8]);
Prefs.setProperty(Prefs.P_THEME, which + "");
}
/**
* Action handler to select color theme.
* @param menu
*/
public void actionTheme(Object menu) {
String which = (String)getProperty(menu, "t");
int t = THEME_DEFAULT;
try {
t = Integer.parseInt(which);
} catch (Exception e) {};
setTheme(t);
}
/**
* Populate a combobox with the current list of analyzers.
* @param combo
*/
public void populateAnalyzers(Object combo) {
removeAll(combo);
String[] aNames = new String[analyzers.length];
for (int i = 0; i < analyzers.length; i++) {
aNames[i] = analyzers[i].getName();
}
Arrays.sort(aNames);
for (int i = 0; i < aNames.length; i++) {
Object choice = create("choice");
setString(choice, "text", aNames[i]);
add(combo, choice);
if (i == 0) {
setString(combo, "text", aNames[i]);
}
}
int lastAnalyzerIdx = 0;
String lastAnalyzer = Prefs.getProperty(Prefs.P_ANALYZER);
if (lastAnalyzer != null) lastAnalyzerIdx = getIndex(combo, lastAnalyzer);
if (lastAnalyzerIdx < 0) lastAnalyzerIdx = 0;
setInteger(combo, "selected", lastAnalyzerIdx);
}
/**
* Return an array of available Analyzer implementations.
* @return
*/
public Class[] getAnalyzers() {
return analyzers;
}
/**
* Loads plugins. Plugins are first searched from the CLASSPATH, and then from a
* plugin list contained in a resource file "/.plugins". The "/.plugins" resource file
* has a simple format - one fully qualified class name per line. Blank lines and
* lines starting with '#' are ignored.
*/
private void loadPlugins() {
List pluginClasses = new ArrayList();
// try to find all plugins
try {
Class classes[] = ClassFinder.getInstantiableSubclasses(LukePlugin.class);
if (classes != null && classes.length > 0) {
pluginClasses.addAll(Arrays.asList(classes));
}
} catch (Exception e) {
e.printStackTrace();
}
// load plugins declared in the ".plugins" file
try {
InputStream is = getClass().getResourceAsStream("/.plugins");
if (is != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = br.readLine()) != null) {
if (line.startsWith("#")) continue;
if (line.trim().equals("")) continue;
try {
Class clazz = Class.forName(line.trim());
if (clazz.getSuperclass().equals(LukePlugin.class) && !pluginClasses.contains(clazz)) {
pluginClasses.add(clazz);
}
} catch (Throwable x) {
//
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
try {
StringBuffer errors = new StringBuffer("Unable to load some plugins:");
boolean failures = false;
for (int i = 0; i < pluginClasses.size(); i++) {
try {
LukePlugin plugin = (LukePlugin) ((Class) pluginClasses.get(i)).getConstructor(new Class[0]).newInstance(
new Object[0]);
String xul = plugin.getXULName();
if (xul == null) continue;
Object ui = parse(xul, plugin);
plugin.setApplication(this);
plugin.setMyUi(ui);
plugins.add(plugin);
} catch (Exception e) {
failures = true;
e.printStackTrace();
errors.append("\n" + pluginClasses.get(i).toString());
}
}
if (failures) {
errorMsg(errors.toString());
}
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.toString());
}
if (plugins.size() == 0) return;
initPlugins();
}
/**
* Create UI for a single plugin.
* @param tabs parent tabbedpane
* @param plugin plugin instance
*/
private void addPluginTab(Object tabs, LukePlugin plugin) {
Object tab = create("tab");
setColor(tab, "foreground", new Color(0x006000));
setString(tab, "text", plugin.getPluginName());
setFont(tab, getFont().deriveFont(Font.BOLD));
add(tabs, tab);
Object panel = create("panel");
setInteger(panel, "gap", 2);
setInteger(panel, "weightx", 1);
setInteger(panel, "weighty", 1);
setChoice(panel, "halign", "fill");
setChoice(panel, "valign", "fill");
setInteger(panel, "columns", 1);
add(tab, panel);
Object infobar = create("panel");
setInteger(infobar, "gap", 8);
setInteger(infobar, "top", 2);
setInteger(infobar, "bottom", 2);
setInteger(infobar, "weightx", 1);
setChoice(infobar, "halign", "fill");
setColor(infobar, "background", new Color(0xc0f0c0));
add(panel, infobar);
Object label = create("label");
setString(label, "text", plugin.getPluginInfo());
add(infobar, label);
Object link = create("button");
setChoice(link, "type", "link");
setString(link, "text", plugin.getPluginHome());
putProperty(link, "url", plugin.getPluginHome());
setMethod(link, "action", "goUrl(this)", infobar, this);
add(infobar, link);
add(panel, create("separator"));
add(panel, plugin.getMyUi());
}
/**
* Return the list of active plugin instances.
* @return
*/
public List<LukePlugin> getPlugins() {
return Collections.unmodifiableList(plugins);
}
/**
* Get an already instantiated plugin, or null if such plugin was
* not loaded on startup.
* @param className fully qualified plugin classname
* @return
*/
public LukePlugin getPlugin(String className) {
for (int i = 0; i < plugins.size(); i++) {
Object plugin = plugins.get(i);
if (plugin.getClass().getName().equals(className))
return (LukePlugin)plugin;
}
return null;
}
Thread statusThread = null;
long lastUpdate = 0;
long statusSleep = 0;
/**
* Display a message on the status bar for 5 seconds.
* @param msg message to display. Too long messages will be truncated by the UI.
*/
public void showStatus(final String msg) {
if (statusThread != null && statusThread.isAlive()) {
setString(statmsg, "text", msg);
statusSleep = 5000;
} else {
statusThread = new Thread() {
public void run() {
statusSleep = 5000;
setString(statmsg, "text", msg);
while (statusSleep > 0) {
try {
sleep(500);
} catch (Exception e) {};
statusSleep -= 500;
}
setString(statmsg, "text", "");
}
};
statusThread.start();
}
}
/**
* As {@link #showStatus(String)} but also sets the "Last search time" label.
* @param msg
*/
public void showSearchStatus(String msg) {
setString(lastST, "text", msg);
showStatus(msg);
}
long lastSlowUpdate = 0L;
long lastSlowCounter = 0L;
Thread slowThread = null;
long slowSleep = 0;
public void showSlowStatus(final String msg, final long counter) {
if (slowThread != null && slowThread.isAlive()) {
lastSlowCounter += counter;
setString(slowmsg, "text", msg + " " + lastSlowCounter);
slowSleep = 5000;
} else {
slowThread = new Thread() {
public void run() {
slowSleep = 5000;
lastSlowCounter = counter;
setBoolean(slowstatus, "visible", true);
setString(slowmsg, "text", msg + " " + lastSlowCounter);
while (slowSleep > 0) {
try {
sleep(500);
} catch (Exception e) {};
slowSleep -= 500;
}
setString(slowmsg, "text", "");
setBoolean(slowstatus, "visible", false);
}
};
slowThread.start();
}
}
/**
* Add a Thinlet component from XUL file.
* @param parent add the new component to this parent
* @param compView path to the XUL resource
* @param handlerStr fully qualified classname of the handler to instantiate,
* or null if the current class will become the handler
* @param argv if not null, these arguments will be passed to the
* appropriate constructor.
* @return
*/
public Object addComponent(Object parent, String compView, String handlerStr, Object[] argv) {
Object res = null;
Object handler = null;
try {
if (handlerStr != null) {
if (argv == null) {
handler = Class.forName(handlerStr).getConstructor(new Class[] { Thinlet.class }).newInstance(
new Object[] { this });
} else {
handler = Class.forName(handlerStr).getConstructor(new Class[] { Thinlet.class, Object[].class })
.newInstance(new Object[] { this, argv });
}
}
if (handler != null) {
res = parse(compView, handler);
} else res = parse(compView);
if (parent != null) {
if (parent instanceof Thinlet)
add(res);
else add(parent, res);
}
return res;
} catch (Exception exc) {
exc.printStackTrace();
errorMsg(exc.getMessage());
return null;
}
}
/**
* Show a modal error dialog with OK button.
* @param msg error message
*/
public void errorMsg(String msg) {
Object fMsg = find(errorDlg, "msg");
setString(fMsg, "text", msg);
add(errorDlg);
}
/**
* Show a modal info dialog with OK button.
* @param msg info message
*/
public void infoMsg(String msg) {
Object fMsg = find(infoDlg, "msg");
setString(fMsg, "text", msg);
add(infoDlg);
}
/**
* Show an "Open Index" dialog.
*
*/
public void actionOpen() {
Object dialog = addComponent(this, "/xml/lukeinit.xml", null, null);
Object path = find(dialog, "path");
if (this.baseDir != null)
setString(path, "text", this.baseDir);
else setString(path, "text", System.getProperty("user.dir"));
}
/**
* Browse for a directory, and put the selection result in the
* indicated widget.
* @param path Thinlet widget to put the result
*/
public void openBrowse(Object path) {
JFileChooser fd = new JFileChooser();
fd.setDialogType(JFileChooser.OPEN_DIALOG);
fd.setDialogTitle("Select Index directory");
fd.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
fd.setFileHidingEnabled(false);
String strPath = getString(path, "text");
if (strPath != null) strPath.trim();
if (strPath != null && strPath.length() > 0)
fd.setCurrentDirectory(new File(strPath));
else if (this.baseDir != null)
fd.setCurrentDirectory(new File(this.baseDir));
else fd.setCurrentDirectory(new File(System.getProperty("user.dir")));
int res = fd.showOpenDialog(this);
File iDir = null;
if (res == JFileChooser.APPROVE_OPTION) iDir = fd.getSelectedFile();
if (iDir != null && iDir.exists()) {
if (!iDir.isDirectory()) iDir = iDir.getParentFile();
setString(path, "text", iDir.toString());
}
}
/**
* Select an output file name, and put the selection result in the
* indicated widget.
* @param path Thinlet widget to put the result
*/
public void saveBrowse(Object path, Object startButton) {
JFileChooser fd = new JFileChooser();
fd.setDialogType(JFileChooser.SAVE_DIALOG);
fd.setDialogTitle("Select Output File");
fd.setFileSelectionMode(JFileChooser.FILES_ONLY);
fd.setFileHidingEnabled(false);
String strPath = getString(path, "text");
if (strPath != null) strPath.trim();
if (strPath != null && strPath.length() > 0)
fd.setCurrentDirectory(new File(strPath));
else if (this.baseDir != null)
fd.setCurrentDirectory(new File(this.baseDir));
else fd.setCurrentDirectory(new File(System.getProperty("user.dir")));
int res = fd.showSaveDialog(this);
setBoolean(startButton, "enabled", false);
File iFile = null;
if (res == JFileChooser.APPROVE_OPTION) iFile = fd.getSelectedFile();
if (iFile != null) {
setString(path, "text", iFile.toString());
setBoolean(startButton, "enabled", true);
}
}
/**
* Initialize MRU list of indexes in the open index dialog.
* @param dialog
*/
public void setupInit(Object dialog) {
Object path = find(dialog, "path");
syncMRU(path);
}
/**
* Attempt to load the index with parameters specified in the dialog.
* <p>NOTE: this method is invoked from the UI. If you need to open an index
* programmatically, you should use {@link #openIndex(String, boolean, boolean, boolean)} instead.</p>
* @param dialog UI dialog with parameters
*/
public void openOk(Object dialog) {
Object path = find(dialog, "path");
pName = getString(path, "text").trim();
boolean force = getBoolean(find(dialog, "force"), "selected");
boolean noReader = getBoolean(find(dialog, "cbNoReader"), "selected");
tiiDiv = 1;
try {
tiiDiv = Integer.parseInt(getString(find(dialog, "tiiDiv"), "text"));
} catch (Exception e) {
e.printStackTrace();
}
Object dirImpl = getSelectedItem(find(dialog, "dirImpl"));
String dirClass = null;
if (dirImpl == null) {
dirClass = FSDirectory.class.getName();
} else {
String name = getString(dirImpl, "name");
if (name == null) {
dirClass = getString(dirImpl, "text");
} else {
if (name.equals("fs")) {
dirClass = FSDirectory.class.getName();
} else if (name.equals("mmap")) {
dirClass = MMapDirectory.class.getName();
} else if (name.equals("niofs")) {
dirClass = NIOFSDirectory.class.getName();
}
}
}
if (pName == null || pName.trim().equals("")) {
errorMsg("Invalid path.");
return;
}
readOnly = getBoolean(find(dialog, "ro"), "selected");
ram = getBoolean(find(dialog, "ram"), "selected");
keepCommits = getBoolean(find(dialog, "cbKeepCommits"), "selected");
slowAccess = getBoolean(find(dialog, "cbSlowIO"), "selected");
decoders.clear();
currentCommit = null;
Prefs.addToMruList(pName);
syncMRU(path);
remove(dialog);
if (noReader) {
removeAll();
addComponent(this, "/xml/luke.xml", null, null);
try {
Directory d = openDirectory(dirClass, pName, false);
if (DirectoryReader.indexExists(d)) {
throw new Exception("there is no valid Lucene index in this directory.");
}
dir = d;
initOverview();
infoMsg("There is no IndexReader - most actions are disabled. " +
"You can open IndexReader from current Directory using 'Re-Open'");
} catch (Exception e) {
errorMsg("ERROR: " + e.toString());
}
} else {
openIndex(pName, force, dirClass, readOnly, ram, keepCommits, null, tiiDiv);
}
}
public void actionClose() {
if (ir != null) {
try {
if (is != null) is = null;
ir.close();
if (ar != null) ar.close();
if (dir != null) dir.close();
} catch (Exception e) {
e.printStackTrace();
errorMsg("Close failed: " + e.getMessage());
}
}
ir = null;
ar = null;
dir = null;
is = null;
removeAll();
addComponent(this, "/xml/luke.xml", null, null);
initPlugins();
}
public void actionCommit() {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (!(ir instanceof DirectoryReader)) {
showStatus("Commit not possible with " + ir.getClass().getSimpleName());
return;
}
if (readOnly) {
showStatus(MSG_READONLY);
return;
}
try {
IndexCommit commit = ((DirectoryReader)ir).getIndexCommit();
Map<String,String> userData = commit.getUserData();
TreeMap<String,String> ud = new TreeMap<String,String>(userData);
Object dialog = addComponent(this, "/xml/commit.xml", null, null);
putProperty(dialog, "userData", ud);
_showUserData(dialog);
} catch (Exception e) {
errorMsg("Exception retrieving user data: " + e.toString());
}
}
private void _showUserData(Object dialog) {
Object table = find(dialog, "data");
removeAll(table);
Map<String,String> ud = (Map<String,String>)getProperty(dialog, "userData");
for (Entry<String,String> e : ud.entrySet()) {
Object row = create("row");
putProperty(row, "key", e.getKey());
add(table, row);
Object cell = create("cell");
setString(cell, "text", e.getKey());
add(row, cell);
cell = create("cell");
setString(cell, "text", e.getValue());
add(row, cell);
}
}
public void putUserData(Object dialog) {
Object key = find(dialog, "key");
Object value = find(dialog, "value");
String k = getString(key, "text");
String v = getString(value, "text");
if (k.equals("")) {
showStatus("Cannot add empty key.");
return;
}
Map<String,String> ud = (Map<String,String>)getProperty(dialog, "userData");
ud.put(k, v);
_showUserData(dialog);
}
public void deleteUserData(Object dialog) {
Object table = find(dialog, "data");
Map<String,String> ud = (Map<String,String>)getProperty(dialog, "userData");
Object[] rows = getSelectedItems(table);
if (rows == null || rows.length == 0) {
return;
}
for (Object row : rows) {
Object key = getProperty(row, "key");
ud.remove(key);
}
_showUserData(dialog);
}
private IndexWriter createIndexWriter() {
try {
IndexWriterConfig cfg = new IndexWriterConfig(LV, new WhitespaceAnalyzer());
IndexDeletionPolicy policy;
if (keepCommits) {
policy = new KeepAllIndexDeletionPolicy();
} else {
policy = new KeepLastIndexDeletionPolicy();
}
cfg.setIndexDeletionPolicy(policy);
MergePolicy mp = cfg.getMergePolicy();
if (mp instanceof LogMergePolicy) {
((LogMergePolicy)mp).setNoCFSRatio(IndexGate.preferCompoundFormat(dir)?1.0:0.0);
} else if (mp instanceof TieredMergePolicy) {
((TieredMergePolicy)cfg.getMergePolicy()).setNoCFSRatio(IndexGate.preferCompoundFormat(dir)?1.0:0.0);
}
IndexWriter iw = new IndexWriter(dir, cfg);
return iw;
} catch (Exception e) {
errorMsg("Error creating IndexWriter: " + e.toString());
return null;
}
}
private void refreshAfterWrite() throws Exception {
actionReopen();
}
public void commitUserData(Object dialog) {
Map<String,String> userData = (Map<String,String>)getProperty(dialog, "userData");
remove(dialog);
if (!(ir instanceof DirectoryReader)) {
errorMsg("Not possible with " + ir.getClass().getSimpleName());
return;
}
try {
IndexWriter iw = createIndexWriter();
iw.setCommitData(userData);
iw.commit();
iw.close();
refreshAfterWrite();
} catch (Exception e) {
errorMsg("Error: " + e.toString());
}
}
public void actionReopen() {
if (dir == null) {
return;
}
openIndex(pName, false, dir.getClass().getName(), readOnly, ram,
keepCommits, currentCommit, tiiDiv);
}
/**
* Open indicated index and re-initialize all GUI and plugins.
* @param pName path to index
* @param force if true, and the index is locked, unlock it first. If false, and
* the index is locked, an error will be reported.
* @param readOnly open in read-only mode, and disallow modifications.
*/
public void openIndex(String name, boolean force, String dirImpl, boolean ro,
boolean ramdir, boolean keepCommits, IndexCommit point, int tiiDivisor) {
pName = name;
readOnly = ro;
removeAll();
File baseFileDir = new File(name);
this.baseDir = baseFileDir.toString();
addComponent(this, "/xml/luke.xml", null, null);
statmsg = find("statmsg");
if (dir != null) {
try {
if (ir != null) ir.close();
if (ar != null) ar.close();
} catch (Exception e) {}
;
try {
if (dir != null) dir.close();
} catch (Exception e) {}
;
}
ArrayList<Directory> dirs = new ArrayList<Directory>();
Throwable lastException = null;
try {
Directory d = openDirectory(dirImpl, pName, false);
if (IndexWriter.isLocked(d)) {
if (!ro) {
if (force) {
IndexWriter.unlock(d);
} else {
errorMsg("Index is locked. Try 'Force unlock' when opening.");
d.close();
d = null;
return;
}
}
}
boolean existsSingle = false;
// IR.indexExists doesn't report the cause of error
try {
new SegmentInfos().read(d);
existsSingle = true;
} catch (Throwable e) {
e.printStackTrace();
lastException = e;
//
}
if (!existsSingle) { // try multi
File[] files = baseFileDir.listFiles();
for (File f : files) {
if (f.isFile()) {
continue;
}
Directory d1 = openDirectory(dirImpl, f.toString(), false);
if (IndexWriter.isLocked(d1)) {
if (!ro) {
if (force) {
IndexWriter.unlock(d1);
} else {
errorMsg("Index is locked. Try 'Force unlock' when opening.");
d1.close();
d1 = null;
return;
}
}
}
existsSingle = false;
try {
new SegmentInfos().read(d1);
existsSingle = true;
} catch (Throwable e) {
lastException = e;
e.printStackTrace();
}
if (!existsSingle) {
d1.close();
continue;
}
dirs.add(d1);
}
} else {
dirs.add(d);
}
if (dirs.size() == 0) {
if (lastException != null) {
errorMsg("Invalid directory at the location, check console for more information. Last exception:\n" + lastException.toString());
} else {
errorMsg("No valid directory at the location, try another location.\nCheck console for other possible causes.");
}
return;
}
if (ramdir) {
showStatus("Loading index into RAMDirectory ...");
Directory dir1 = new RAMDirectory();
IndexWriterConfig cfg = new IndexWriterConfig(LV, new WhitespaceAnalyzer());
IndexWriter iw1 = new IndexWriter(dir1, cfg);
iw1.addIndexes((Directory[])dirs.toArray(new Directory[dirs.size()]));
iw1.close();
showStatus("RAMDirectory loading done!");
if (dir != null) dir.close();
dirs.clear();
dirs.add(dir1);
}
IndexDeletionPolicy policy;
if (keepCommits) {
policy = new KeepAllIndexDeletionPolicy();
} else {
policy = new KeepLastIndexDeletionPolicy();
}
ArrayList<DirectoryReader> readers = new ArrayList<DirectoryReader>();
for (Directory dd : dirs) {
DirectoryReader reader;
if (tiiDivisor > 1) {
reader = DirectoryReader.open(dd, tiiDivisor);
} else {
reader = DirectoryReader.open(dd);
}
readers.add(reader);
}
if (readers.size() == 1) {
ir = readers.get(0);
dir = ((DirectoryReader)ir).directory();
} else {
ir = new MultiReader((IndexReader[])readers.toArray(new IndexReader[readers.size()]));
}
is = new IndexSearcher(ir);
// XXX
slowAccess = false;
initOverview();
initPlugins();
showStatus("Index successfully open.");
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.getMessage());
return;
}
}
/**
* Open a single directory.
* @param dirImpl fully-qualified class name of Directory implementation,
* or "FSDirectory" for {@link FSDirectory}
* @param file index directory
* @param create if true, create a new directory
* @return directory implementation
*/
Class defaultDirImpl = null;
public Directory openDirectory(String dirImpl, String file, boolean create) throws Exception {
File f = new File(file);
if (!f.exists()) {
throw new Exception("Index directory doesn't exist.");
}
Directory res = null;
if (dirImpl == null || dirImpl.equals(Directory.class.getName()) || dirImpl.equals(FSDirectory.class.getName())) {
return FSDirectory.open(f);
}
try {
Class implClass = Class.forName(dirImpl);
Constructor<Directory> constr = implClass.getConstructor(File.class);
if (constr != null) {
res = constr.newInstance(f);
} else {
constr = implClass.getConstructor(File.class, LockFactory.class);
res = constr.newInstance(f, (LockFactory)null);
}
} catch (Throwable e) {
errorMsg("Invalid directory implementation class: " + dirImpl + " " + e);
return null;
}
if (res != null) return res;
// fall-back to FSDirectory.
if (res == null) return FSDirectory.open(f);
return null;
}
/**
* Indicates whether I/O access should be optimized because
* the index is on a slow medium (e.g. remote).
* @return true if I/O access is costly and should be minimized
*/
public boolean isSlowAccess() {
return slowAccess;
}
/**
* Set whether the I/O access to this index is costly and
* should be minimized.
*/
public void setSlowAccess(boolean slowAccess) {
this.slowAccess = slowAccess;
if (slowAccess) {
}
}
/**
* Initialize plugins. This method should always be called when a new index is open.
*
*/
public void initPlugins() {
Object pluginsTabs = find("pluginsTabs");
removeAll(pluginsTabs);
for (int i = 0; i < plugins.size(); i++) {
LukePlugin plugin = (LukePlugin) plugins.get(i);
addPluginTab(pluginsTabs, plugin);
plugin.setDirectory(dir);
plugin.setReader(ir);
try {
plugin.init();
} catch (Exception e) {
e.printStackTrace();
showStatus("PLUGIN ERROR: " + e.getMessage());
}
}
}
/**
* Initialize index overview and other GUI elements. This method is called always
* when a new index is open.
*
*/
private void initOverview() {
try {
initSolrTypes();
courier = new Font("Courier", getFont().getStyle(), getFont().getSize());
lastST = find("lastST");
setBoolean(find("bReload"), "enabled", true);
setBoolean(find("bClose"), "enabled", true);
setBoolean(find("bCommit"), "enabled", true);
Object sTable = find("sTable");
removeAll(sTable);
Object docTable = find("docTable");
removeAll(docTable);
Object cbType = find("cbType");
populateAnalyzers(cbType);
Object pOver = find("pOver");
Object iName = find("idx");
String idxName;
if (pName.length() > 40) {
idxName = pName.substring(0, 10) + "..." + pName.substring(pName.length() - 27);
} else {
idxName = pName;
}
setString(iName, "text", idxName + (readOnly ? " (R)" : ""));
iName = find(pOver, "iName");
setString(iName, "text", pName + (readOnly ? " (Read-Only)" : ""));
Object dirImpl = find("dirImpl");
String implName = "N/A";
if (dir == null) {
if (ir != null) {
implName = "N/A (reader is " + ir.getClass().getName() + ")";
}
} else {
implName = dir.getClass().getName();
}
setString(dirImpl, "text", implName);
Object fileSize = find("iFileSize");
long totalFileSize = Util.calcTotalFileSize(pName, dir);
setString(fileSize, "text", Util.normalizeSize(totalFileSize) + Util.normalizeUnit(totalFileSize));
Object iFormat = find(pOver, "iFormat");
Object iCaps = find(pOver, "iCaps");
String formatText = "N/A";
String formatCaps = "N/A";
if (dir != null) {
IndexGate.FormatDetails formatDetails = IndexGate.getIndexFormat(dir);
formatText = formatDetails.genericName;
formatCaps = formatDetails.capabilities;
}
setString(iFormat, "text", formatText);
setString(iCaps, "text", formatCaps);
if (ir == null) {
return;
}
// we need IndexReader from now on
idxInfo = new IndexInfo(ir, pName);
Object iDocs = find(pOver, "iDocs");
String numdocs = String.valueOf(ir.numDocs());
setString(iDocs, "text", numdocs);
iDocs = find("iDocs1");
setString(iDocs, "text", String.valueOf(ir.maxDoc() - 1));
Object iFields = find(pOver, "iFields");
fn = idxInfo.getFieldNames();
if (fn.size() == 0) {
showStatus("Empty index.");
}
showFiles(dir, null);
if (ir instanceof CompositeReader) {
ar = SlowCompositeReaderWrapper.wrap((CompositeReader)ir);
} else if (ir instanceof AtomicReader) {
ar = (AtomicReader)ir;
}
if (ar != null) {
infos = ar.getFieldInfos();
}
showCommits();
final Object fList = find(pOver, "fList");
final Object defFld = find("defFld");
final Object fCombo = find("fCombo");
TreeSet<String> fields = new TreeSet<String>(fn);
idxFields = (String[])fields.toArray(new String[fields.size()]);
setString(iFields, "text", String.valueOf(idxFields.length));
final Object iTerms = find(pOver, "iTerms");
if (!slowAccess) {
Thread t = new Thread() {
public void run() {
Object r = create("row");
Object cell = create("cell");
add(r, cell);
add(fList, r);
setBoolean(cell, "enabled", false);
setString(cell, "text", "..wait..");
try {
numTerms = idxInfo.getNumTerms();
termCounts = idxInfo.getFieldTermCounts();
setString(iTerms, "text", String.valueOf(numTerms));
initFieldList(fList, fCombo, defFld);
} catch (Exception e) {
e.printStackTrace();
numTerms = -1;
termCounts = Collections.emptyMap();
showStatus("ERROR: can't count terms per field");
}
}
};
t.start();
} else {
setString(iTerms, "text", "N/A");
initFieldList(fList, fCombo, defFld);
}
Object iDel = find(pOver, "iDelOpt");
String sDel = ir.hasDeletions() ? "Yes (" + ir.numDeletedDocs() + ")" : "No";
IndexCommit ic = ir instanceof DirectoryReader ? ((DirectoryReader)ir).getIndexCommit() : null;
String opt = ic != null ? (ic.getSegmentCount() == 1 ? "Yes" : "No") : "?";
String sDelOpt = sDel + " / " + opt;
setString(iDel, "text", sDelOpt);
Object iVer = find(pOver, "iVer");
String verText = "N/A";
if (ic != null) {
verText = Long.toHexString(((DirectoryReader)ir).getVersion());
}
setString(iVer, "text", verText);
Object iTiiDiv = find(pOver, "iTiiDiv");
String divText = "N/A";
if (ir instanceof DirectoryReader) {
List<AtomicReaderContext> readers = ((DirectoryReader)ir).leaves();
if (readers.size() > 0 && readers.get(0).reader() instanceof SegmentReader){
divText = String.valueOf(((SegmentReader)(readers.get(0)).reader()).getTermInfosIndexDivisor());
}
}
setString(iTiiDiv, "text", divText);
Object iCommit = find(pOver, "iCommit");
String commitText = "N/A";
if (ic != null) {
commitText = ic.getSegmentsFileName() +
" (generation=" + ic.getGeneration() + ", segs=" +
ic.getSegmentCount() + ")";
}
setString(iCommit, "text", commitText);
Object iUser = find(pOver, "iUser");
String userData = null;
if (ic != null) {
Map<String,String> userDataMap = ic.getUserData();
if (userDataMap != null && !userDataMap.isEmpty()) {
userData = userDataMap.toString();
} else {
userData = "--";
}
} else {
userData = "(not supported)";
}
setString(iUser, "text", userData);
final Object nTerms = find("nTerms");
if (!slowAccess) {
Thread t = new Thread() {
public void run() {
actionTopTerms(nTerms);
}
};
t.start();
}
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.getMessage());
}
}
private void initFieldList(Object fList, Object fCombo, Object defFld) {
removeAll(fList);
removeAll(fCombo);
removeAll(defFld);
setString(fCombo, "text", idxFields[0]);
setString(defFld, "text", idxFields[0]);
NumberFormat intCountFormat = NumberFormat.getIntegerInstance();
NumberFormat percentFormat = NumberFormat.getNumberInstance();
intCountFormat.setGroupingUsed(true);
percentFormat.setMaximumFractionDigits(2);
// sort by names now
for (String s : idxFields) {
Object row = create("row");
putProperty(row, "fName", s);
add(fList, row);
Object cell = create("cell");
setString(cell, "text", s);
add(row, cell);
if (termCounts != null) {
cell = create("cell");
FieldTermCount ftc = termCounts.get(s);
if (ftc != null) {
long cnt = ftc.termCount;
setString(cell, "text", intCountFormat.format(cnt));
setChoice(cell, "alignment", "right");
add(row, cell);
float pcent = (float)(cnt * 100) / (float)numTerms;
cell = create("cell");
setString(cell, "text", percentFormat.format(pcent) + " %");
setChoice(cell, "alignment", "right");
add(row, cell);
} else {
setString(cell, "text", "0");
setChoice(cell, "alignment", "right");
add(row, cell);
cell = create("cell");
setString(cell, "text", "0.00 %");
setChoice(cell, "alignment", "right");
add(row, cell);
}
} else {
cell = create("cell");
setString(cell, "text", "N/A");
add(row, cell);
cell = create("cell");
add(row, cell);
}
cell = create("cell");
setChoice(cell, "alignment", "right");
Decoder dec = decoders.get(s);
if (dec == null) dec = defDecoder;
setString(cell, "text", dec.toString());
add(row, cell);
// populate combos
Object choice = create("choice");
add(fCombo, choice);
setString(choice, "text", s);
putProperty(choice, "fName", s);
choice = create("choice");
add(defFld, choice);
setString(choice, "text", s);
putProperty(choice, "fName", s);
}
setString(find("defFld"), "text", idxFields[0]);
// Remove columns
Object header = get(find("sTable"), "header");
removeAll(header);
Object c = create("column");
setString(c, "text", "#");
setInteger(c, "width", 40);
add(header, c);
c = create("column");
setString(c, "text", "Score");
setInteger(c, "width", 50);
add(header, c);
c = create("column");
setString(c, "text", "Doc. Id");
setInteger(c, "width", 60);
add(header, c);
for (int j = 0; j < idxFields.length; j++) {
c = create("column");
setString(c, "text", idxFields[j]);
add(header, c);
}
}
private void showCommits() throws Exception {
Object commitsTable = find("commitsTable");
removeAll(commitsTable);
if (dir == null) {
Object row = create("row");
Object cell = create("cell");
setString(cell, "text", "<not available>");
setBoolean(cell, "enabled", false);
add(row, cell);
add(commitsTable, row);
return;
}
List<IndexCommit> commits = DirectoryReader.listCommits(dir);
IndexCommit current = ir instanceof DirectoryReader ? ((DirectoryReader)ir).getIndexCommit() : null;
// commits are ordered from oldest to newest ?
Iterator<IndexCommit> it = commits.iterator();
int rowNum = 0;
while (it.hasNext()) {
IndexCommit commit = (IndexCommit)it.next();
// figure out the name of the segment files
Collection<String> files = commit.getFileNames();
Iterator<String> itf = files.iterator();
Object row = create("row");
boolean enabled = rowNum < commits.size() - 1;
Color color = Color.BLUE;
rowNum++;
add(commitsTable, row);
putProperty(row, "commit", commit);
if (enabled) {
putProperty(row, "commitDeletable", Boolean.TRUE);
}
Object cell = create("cell");
String gen = String.valueOf(commit.getGeneration());
setString(cell, "text", gen);
add(row, cell);
cell = create("cell");
setString(cell, "text", commit.isDeleted() ? "Y" : "N");
add(row, cell);
cell = create("cell");
setString(cell, "text", String.valueOf(commit.getSegmentCount()));
add(row, cell);
cell = create("cell");
Map userData = commit.getUserData();
if (userData != null && !userData.isEmpty()) {
setString(cell, "text", userData.toString());
} else {
setString(cell, "text", "");
}
add(row, cell);
if (commit.equals(current)) {
Object[] cells = getItems(row);
for (Object c : cells) {
setColor(c, "foreground", color);
}
}
}
}
public void showSegments(Object commitsTable) throws Exception {
Object segTable = find("segmentsTable");
removeAll(segTable);
Object[] rows = getSelectedItems(commitsTable);
if (rows == null || rows.length == 0) {
showStatus("No commit point selected.");
return;
}
Object row = rows[0];
IndexCommit commit = (IndexCommit)getProperty(row, "commit");
if (commit == null) {
showStatus("Can't retrieve commit point (application error)");
return;
}
Object segGen = find("segGen");
setString(segGen, "text", commit.getSegmentsFileName() + " (gen " + commit.getGeneration() + ")");
String segName = commit.getSegmentsFileName();
SegmentInfos infos = new SegmentInfos();
try {
infos.read(dir, segName);
} catch (Exception e) {
e.printStackTrace();
errorMsg("Error reading segment infos for '" + segName + ": " + e.toString());
return;
}
for (SegmentCommitInfo si : infos.asList()) {
Object r = create("row");
add(segTable, r);
Object cell = create("cell");
add(r, cell);
setString(cell, "text", si.info.name);
cell = create("cell");
add(r, cell);
setString(cell, "text", String.valueOf(si.getDelGen()));
setChoice(cell, "alignment", "right");
cell = create("cell");
add(r, cell);
setString(cell, "text", String.valueOf(si.getDelCount()));
setChoice(cell, "alignment", "right");
cell = create("cell");
add(r, cell);
setString(cell, "text", String.valueOf(si.info.getDocCount()));
setChoice(cell, "alignment", "right");
cell = create("cell");
add(r, cell);
setString(cell, "text", si.info.getVersion().toString());
cell = create("cell");
add(r, cell);
setString(cell, "text", si.info.getCodec().getName());
long size = si.sizeInBytes();
cell = create("cell");
add(r, cell);
setString(cell, "text", Util.normalizeSize(size) + Util.normalizeUnit(size));
setChoice(cell, "alignment", "right");
cell = create("cell");
add(r, cell);
setString(cell, "text", si.info.getUseCompoundFile() ? "Y" : "N");
putProperty(r, "si", si);
}
Object diagsTable = find("diagsTable");
removeAll(diagsTable);
}
public void showDiagnostics(Object segmentsTable) {
Object diagsTable = find("diagsTable");
removeAll(diagsTable);
Object row = getSelectedItem(segmentsTable);
if (row == null) {
return;
}
SegmentCommitInfo si = (SegmentCommitInfo)getProperty(row, "si");
if (si == null) {
showStatus("Missing SegmentInfoPerCommit???");
return;
}
//deprecated call below
// map = si.info.attributes();
// if (map != null) {
// for (Entry<String,String> e : map.entrySet()) {
// Object r = create("row");
// add(diagsTable, r);
// Object cell = create("cell");
// setString(cell, "text", "A");
// add(r, cell);
// cell = create("cell");
// setString(cell, "text", e.getKey());
// add(r, cell);
// cell = create("cell");
// setString(cell, "text", e.getValue());
// add(r, cell);
// }
// };
// separator
// Object r1 = create("row");
// add(diagsTable, r1);
// Object c1 = create("cell");
// setBoolean(c1, "enabled", false);
// add(r1, c1);
Map<String,String> map = si.info.getDiagnostics();
if (map != null) {
for (Entry<String,String> e : map.entrySet()) {
Object r = create("row");
add(diagsTable, r);
Object cell = create("cell");
setString(cell, "text", "D");
add(r, cell);
cell = create("cell");
setString(cell, "text", e.getKey());
add(r, cell);
cell = create("cell");
setString(cell, "text", e.getValue());
add(r, cell);
}
}
// separator
Object r1 = create("row");
add(diagsTable, r1);
Object c1 = create("cell");
setBoolean(c1, "enabled", false);
add(r1, c1);
// codec info
Codec codec = si.info.getCodec();
map = new LinkedHashMap<String,String>();
map.put("codecName", codec.getName());
map.put("codecClassName", codec.getClass().getName());
map.put("docValuesFormat", codec.docValuesFormat().getClass().getName());
map.put("fieldInfosFormat", codec.fieldInfosFormat().getClass().getName());
map.put("liveDocsFormat", codec.liveDocsFormat().getClass().getName());
map.put("normsFormat", codec.normsFormat().getClass().getName());
map.put("postingsFormat", codec.postingsFormat().toString() + " " + codec.postingsFormat().getClass().getName());
map.put("segmentInfoFormat", codec.segmentInfoFormat().getClass().getName());
map.put("storedFieldsFormat", codec.storedFieldsFormat().getClass().getName());
map.put("termVectorsFormat", codec.termVectorsFormat().getClass().getName());
try {
List<String> files = new ArrayList<String>(si.files());
Collections.sort(files);
map.put("---files---", files.toString());
if (si.info.getUseCompoundFile()) {
Directory d = new CompoundFileDirectory(dir, IndexFileNames.segmentFileName(si.info.name, "", IndexFileNames.COMPOUND_FILE_EXTENSION), IOContext.READ, false);
files.clear();
files.addAll(Arrays.asList(d.listAll()));
d.close();
Collections.sort(files);
map.put("-CFS-files-", files.toString());
}
} catch (Exception e) {
e.printStackTrace();
map.put("---files---", "Exception: " + e.toString());
}
for (Entry<String,String> e : map.entrySet()) {
Object r = create("row");
add(diagsTable, r);
Object cell = create("cell");
setString(cell, "text", "C");
add(r, cell);
cell = create("cell");
setString(cell, "text", e.getKey());
add(r, cell);
cell = create("cell");
setString(cell, "text", e.getValue());
add(r, cell);
}
// fieldInfos
try {
SegmentReader sr = new SegmentReader(si, 1, IOContext.READ);
FieldInfos fis = sr.getFieldInfos();
map = new LinkedHashMap<String,String>();
List<String> flds = new ArrayList<String>(fis.size());
for (FieldInfo fi : fis) {
flds.add(fi.name);
}
Collections.sort(flds);
map.put("L---fields---", flds.toString());
for (String fn : flds) {
FieldInfo fi = fis.fieldInfo(fn);
map.put("A" + fi.name, fi.attributes().toString());
}
map.put("F---flags----", "IdfpoPVNtxxDtxx");
for (String fn : flds) {
FieldInfo fi = fis.fieldInfo(fn);
map.put("F" + fi.name, Util.fieldFlags(null, fi));
}
sr.close();
// separator
r1 = create("row");
add(diagsTable, r1);
c1 = create("cell");
setBoolean(c1, "enabled", false);
add(r1, c1);
for (Entry<String,String> e : map.entrySet()) {
Object r = create("row");
add(diagsTable, r);
Object cell = create("cell");
setString(cell, "text", "F" + e.getKey().charAt(0));
add(r, cell);
cell = create("cell");
setString(cell, "text", e.getKey().substring(1));
add(r, cell);
cell = create("cell");
setString(cell, "text", e.getValue());
if (e.getKey().startsWith("F")) {
setFont(cell, courier);
}
add(r, cell);
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void openCommit(Object commitsTable) throws IOException {
Object row = getSelectedItem(commitsTable);
if (row == null) {
showStatus("No commit point selected.");
return;
}
IndexCommit commit = (IndexCommit)getProperty(row, "commit");
if (commit == null) {
showStatus("Can't retrieve commit point (application error)");
return;
}
IndexCommit current = ir instanceof DirectoryReader ? ((DirectoryReader)ir).getIndexCommit() : null;
if (commit.equals(current)) {
showStatus("Already open at this commit point.");
return;
}
ir.close();
IndexDeletionPolicy policy;
if (keepCommits) {
policy = new KeepAllIndexDeletionPolicy();
} else {
policy = new KeepLastIndexDeletionPolicy();
}
ir = DirectoryReader.open(commit);
initOverview();
}
public void showCommitFiles(Object commitTable) throws Exception {
List<IndexCommit> commits = new ArrayList<IndexCommit>();
Object[] rows = getSelectedItems(commitTable);
if (rows == null || rows.length == 0) {
showFiles(dir, commits);
return;
}
for (int i = 0; i < rows.length; i++) {
IndexCommit commit = (IndexCommit)getProperty(rows[i], "commit");
if (commit != null) {
commits.add(commit);
}
}
showFiles(dir, commits);
showSegments(commitTable);
}
private void showFiles(Directory dir, List<IndexCommit> commits) throws Exception {
Object filesTable = find("filesTable");
if (dir == null) {
removeAll(filesTable);
Object row = create("row");
Object cell = create("cell");
setString(cell, "text", "<not available>");
setBoolean(cell, "enabled", false);
add(row, cell);
add(filesTable, row);
return;
}
Object iFileSize = find("iFileSize");
long totalSize = 0;
String[] physFiles = dir.listAll();
Set<String> files = new HashSet<String>();
if (commits != null && commits.size() > 0) {
for (int i = 0; i < commits.size(); i++) {
IndexCommit commit = commits.get(i);
files.addAll(commit.getFileNames());
}
} else {
files.addAll(Arrays.asList(physFiles));
}
List<String> uFiles = new ArrayList<String>(files);
Collections.sort(uFiles);
List<String> segs = getIndexFileNames(dir);
List<String> dels = getIndexDeletableNames(dir);
Font courier2 = courier.deriveFont((float)courier.getSize() * 1.1f);
removeAll(filesTable);
for (int i = 0; i < uFiles.size(); i++) {
String fileName = uFiles.get(i);
String pathName;
if (pName.endsWith(File.separator)) {
pathName = pName;
} else {
pathName = pName + File.separator;
}
File file = new File(pathName + fileName);
boolean deletable = dels.contains(fileName.intern());
String inuse = getFileFunction(fileName);
Object row = create("row");
Object nameCell = create("cell");
setString(nameCell, "text", fileName);
setString(nameCell, "tooltip", inuse);
add(row, nameCell);
Object sizeCell = create("cell");
long length = file.length();
totalSize += length;
setString(sizeCell, "text", Util.normalizeSize(length) + Util.normalizeUnit(length));
setChoice(sizeCell, "alignment", "right");
setFont(sizeCell, courier2);
add(row, sizeCell);
Object delCell = create("cell");
setString(delCell, "text", deletable ? "YES" : "-");
add(row, delCell);
Object inuseCell = create("cell");
setString(inuseCell, "text", inuse);
add(row, inuseCell);
add(filesTable, row);
}
setString(iFileSize, "text", Util.normalizeSize(totalSize) + Util.normalizeUnit(totalSize));
}
private String getFileFunction(String file) {
String res = IndexGate.getFileFunction(file);
if (res == null) {
res = "YES";
}
return res;
}
private void syncMRU(Object path) {
removeAll(path);
for (Iterator iter = Prefs.getMruList().iterator(); iter.hasNext();) {
String element = (String) iter.next();
Object choice = create("choice");
setString(choice, "text", element);
add(path, choice);
}
}
/**
* Update the list of top terms.
* @param nTerms Thinlet widget containing the number of top terms to show
*/
public void actionTopTerms(Object nTerms) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
String sndoc = getString(nTerms, "text");
int nd = 50;
try {
nd = Integer.parseInt(sndoc);
} catch (Exception e) {}
final int ndoc = nd;
Object[] fields = getSelectedItems(find("fList"));
String[] flds = null;
if (fields == null || fields.length == 0) {
flds = idxFields;
} else {
flds = new String[fields.length];
for (int i = 0; i < fields.length; i++) {
flds[i] = (String) getProperty(fields[i], "fName");
}
}
final String[] fflds = flds;
SlowThread st = new SlowThread(this) {
public void execute() {
try {
TermStats[] topTerms = HighFreqTerms.getHighFreqTerms(ir, ndoc, fflds);
Object table = find("tTable");
removeAll(table);
if (topTerms == null || topTerms.length == 0) {
Object row = create("row");
Object cell = create("cell");
add(row, cell);
cell = create("cell");
add(row, cell);
cell = create("cell");
add(row, cell);
cell = create("cell");
setBoolean(cell, "enabled", false);
setString(cell, "text", "No Results");
add(row, cell);
add(table, row);
return;
}
for (int i = 0; i < topTerms.length; i++) {
Object row = create("row");
add(table, row);
putProperty(row, "term", new Term(topTerms[i].field, topTerms[i].termtext));
putProperty(row, "ti", topTerms[i]);
Object cell = create("cell");
setChoice(cell, "alignment", "right");
setString(cell, "text", String.valueOf(i + 1));
add(row, cell);
cell = create("cell");
setChoice(cell, "alignment", "right");
setString(cell, "text", String.valueOf(topTerms[i].docFreq) + " ");
add(row, cell);
cell = create("cell");
setString(cell, "text", topTerms[i].field);
add(row, cell);
cell = create("cell");
Decoder dec = decoders.get(topTerms[i].field);
if (dec == null) dec = defDecoder;
String s;
try {
s = dec.decodeTerm(topTerms[i].field, topTerms[i].termtext.utf8ToString());
} catch (Throwable e) {
//e.printStackTrace();
s = topTerms[i].termtext.utf8ToString();
setColor(cell, "foreground", Color.RED);
}
setString(cell, "text", " " + s);
add(row, cell);
}
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void clipTopTerms(Object tTable) {
Object[] rows = getItems(tTable);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < rows.length; i++) {
TermStats ti = (TermStats)getProperty(rows[i], "ti");
if (ti == null) continue;
sb.append(ti.docFreq + "\t" + ti.field + "\t" + ti.termtext.utf8ToString() + "\n");
}
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
/**
* Switch to a view that shows all documents containing selected term.
* @param tTable Thinlet table widget, where selected row contains a property named "term",
* which is the selected {@link Term} instance
*/
public void browseTermDocs(Object tTable) {
Object row = getSelectedItem(tTable);
if (row == null) return;
Term t = (Term) getProperty(row, "term");
if (t == null) return;
Object tabpane = find("maintpane");
setInteger(tabpane, "selected", 1);
_showTerm(find("fCombo"), find("fText"), t);
showFirstTermDoc(find("fText"));
repaint();
}
public void showTermDocs(Object tTable) {
Object row = getSelectedItem(tTable);
if (row == null) return;
Term t = (Term) getProperty(row, "term");
if (t == null) return;
Object tabpane = find("maintpane");
setInteger(tabpane, "selected", 2);
Object qField = find("qField");
setString(qField, "text", t.field() + ":" + t.text());
search(qField);
repaint();
}
/**
* Undelete all deleted documents in the current index. This method also
* updates the overview.
*/
public void actionUndelete() {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (readOnly) {
showStatus(MSG_READONLY);
return;
}
if (!(ir instanceof DirectoryReader)) {
showStatus("Not possible with " + ir.getClass().getSimpleName());
return;
}
errorMsg("Not supported in Lucene 4 API");
/*
try {
ir.undeleteAll();
initOverview();
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.getMessage());
}
*/
}
/** Not implemented yet... */
public void actionConvert(Object method) {
}
public List<String> getIndexDeletableNames(Directory d) {
if (d == null) return null;
List<String> deletable = null;
try {
deletable = IndexGate.getDeletableFiles(d);
} catch (Exception e) {
e.printStackTrace();
}
//for (int i = 0; i < deletable.size(); i++) {
// System.out.println(" -del " + deletable.get(i));
//}
if (deletable == null) deletable = Collections.EMPTY_LIST;
return deletable;
}
public Directory getDirectory() {
return dir;
}
public IndexReader getIndexReader() {
return ir;
}
public void setIndexReader(IndexReader reader, String indexName) {
if (reader == null) {
return;
}
try {
if (is != null) {
is = null;
}
if (ir != null) {
ir.close();
ir = null;
}
if (ar != null) {
ar.close();
ar = null;
}
if (dir != null) {
dir.close();
dir = null;
}
if (reader instanceof DirectoryReader) {
dir = ((DirectoryReader)reader).directory();
} else {
dir = null;
}
ir = reader;
is = new IndexSearcher(ir);
pName = indexName;
initOverview();
initPlugins();
} catch (Exception e) {
e.printStackTrace();
errorMsg("Setting new IndexReader failed: " + e.toString());
}
}
public List<String> getIndexFileNames(Directory d) {
if (d == null) return null;
List<String> names = null;
try {
names = IndexGate.getIndexFiles(d);
} catch (Exception e) {
e.printStackTrace();
}
//for (int i = 0; i < names.size(); i++) {
// System.out.println(" -seg " + names.get(i));
//}
return names;
}
public void actionCheckIndex() {
if (dir == null) {
errorMsg("No directory - open index directory first (you may use the 'no IndexReader' option).");
return;
}
Object dialog = addComponent(null, "/xml/checkindex.xml", null, null);
Object dirName = find(dialog, "dirName");
setString(dirName, "text", pName);
add(dialog);
}
public void checkIndex(final Object dialog) {
Thread t = new Thread() {
public void run() {
Object panel = find(dialog, "msg");
Object fixPanel = find(dialog, "fixPanel");
PanelPrintWriter ppw = new PanelPrintWriter(Luke.this, panel);
Object ckRes = find(dialog, "ckRes");
CheckIndex.Status status = null;
CheckIndex ci = new CheckIndex(dir);
ci.setInfoStream(ppw);
putProperty(dialog, "checkIndex", ci);
putProperty(dialog, "ppw", ppw);
try {
status = ci.checkIndex();
} catch (Exception e) {
ppw.println("ERROR: caught exception, giving up.\n\n");
e.printStackTrace();
e.printStackTrace(ppw);
}
if (status != null) {
Luke.this.putProperty(dialog, "checkStatus", status);
String statMsg;
if (status.clean) {
statMsg = "OK";
} else if (status.toolOutOfDate) {
statMsg = "ERROR: Can't check - tool out-of-date";
} else {
// show fixPanel
setBoolean(fixPanel, "visible", true);
repaint(dialog);
statMsg = "BAD: ";
if (status.cantOpenSegments) {
statMsg += "cantOpenSegments ";
}
if (status.missingSegments) {
statMsg += "missingSegments ";
}
if (status.missingSegmentVersion) {
statMsg += "missingSegVersion ";
}
if (status.numBadSegments > 0) {
statMsg += "numBadSegments=" + status.numBadSegments + " ";
}
if (status.totLoseDocCount > 0) {
statMsg += "lostDocCount=" + status.totLoseDocCount + " ";
}
}
setString(ckRes, "text", statMsg);
}
}
};
t.start();
}
public void fixIndex(final Object dialog) {
Thread t = new Thread() {
public void run(){
CheckIndex ci = (CheckIndex)getProperty(dialog, "checkIndex");
if (ci == null) {
errorMsg("You need to run 'Check Index' first.");
return;
}
CheckIndex.Status status = (CheckIndex.Status)getProperty(dialog, "checkStatus");
if (status == null) {
errorMsg("You need to run 'Check Index' first.");
return;
}
// use codec from the first valid segment
Codec c = null;
for (SegmentInfoStatus ssi : status.segmentInfos) {
if (ssi.codec != null) {
c = ssi.codec;
break;
}
}
if (c == null) {
showStatus("Can't determine Codec, using default");
c = Codec.getDefault();
}
Object fixRes = find(dialog, "fixRes");
PanelPrintWriter ppw = (PanelPrintWriter)getProperty(dialog, "ppw");
try {
ci.fixIndex(status);
setString(fixRes, "text", "DONE. Review the output above.");
} catch (Exception e) {
ppw.println("\nERROR during Fix Index:");
e.printStackTrace(ppw);
setString(fixRes, "text", "FAILED. Review the output above.");
}
}
};
t.start();
}
public boolean isFSBased(Directory dir) {
if (dir == null) {
return false;
}
if (dir instanceof MMapDirectory ||
dir instanceof NIOFSDirectory ||
dir instanceof FSDirectory) {
return true;
}
return false;
}
/**
* This method will cleanup the current Directory of any content
* that is not the part of the index.
*/
public void actionCleanup() {
if (dir == null) {
showStatus(MSG_NOINDEX);
return;
}
try {
List allFiles;
boolean phys = false;
if (isFSBased(dir)) {
File phyDir = new File(pName);
phys = true;
allFiles = new ArrayList(Arrays.asList(phyDir.list()));
} else {
allFiles = new ArrayList(Arrays.asList(dir.listAll()));
}
List indexFiles = getIndexFileNames(dir);
allFiles.removeAll(indexFiles);
if (allFiles.size() == 0) {
infoMsg("There are no files to be cleaned - target directory contains only index-related files.");
return;
}
Object dialog = addComponent(null, "/xml/cleanup.xml", null, null);
Object filesTable = find(dialog, "filesTable");
for (int i = 0; i < allFiles.size(); i++) {
String fileName = (String)allFiles.get(i);
Object row = create("row");
add(filesTable, row);
putProperty(row, "fileName", fileName);
long size = dir.fileLength(fileName);
Object cell;
cell = create("cell");
setString(cell, "text", Util.normalizeSize(size));
add(row, cell);
cell = create("cell");
setString(cell, "text", Util.normalizeUnit(size));
add(row, cell);
cell = create("cell");
setString(cell, "text", fileName);
add(row, cell);
}
add(dialog);
} catch (Exception e) {
errorMsg("Error: " + e.toString());
}
}
public void toggleKeep(Object filesTable) {
Object[] rows = getSelectedItems(filesTable);
if (rows == null || rows.length == 0) return;
for (int i = 0; i < rows.length; i++) {
Boolean Deletable = (Boolean)getProperty(rows[i], "deletable");
boolean deletable = Deletable != null ? Deletable.booleanValue() : true;
deletable = !deletable;
putProperty(rows[i], "deletable", Boolean.valueOf(deletable));
Object[] cells = getItems(rows[i]);
for (int k = 0; k < cells.length; k++) {
if (!deletable) {
setBoolean(cells[k], "enabled", false);
} else {
setBoolean(cells[k], "enabled", true);
}
}
}
repaint(filesTable);
}
public void _actionCleanup(Object filesTable) {
try {
if (is != null) {
is = null;
}
if (ir != null) {
ir.close();
}
if (ar != null) {
ar.close();
}
} catch (Exception e) {
e.printStackTrace();
}
ArrayList noDel = new ArrayList();
String errMsg = null;
boolean phys = isFSBased(dir);
int deleted = 0;
try {
Object[] rows = getItems(filesTable);
for (int i = 0; i < rows.length; i++) {
String name = (String)getProperty(rows[i], "fileName");
Boolean Deletable = (Boolean)getProperty(rows[i], "deletable");
boolean deletable = Deletable != null ? Deletable.booleanValue() : true;
if (!deletable) {
continue;
}
if (phys) {
File f = new File(pName, name);
if (!removeFile(f)) {
noDel.add(name);
}
deleted++;
continue;
} else {
dir.deleteFile(name);
deleted++;
}
}
if (noDel.size() > 0) {
StringBuffer msg = new StringBuffer("Some files could not be deleted:");
for (int i = 0; i < noDel.size(); i++) msg.append("\n" + noDel.get(i));
errMsg = msg.toString();
}
} catch (Exception e) {
e.printStackTrace();
errMsg = "FAILED: " + e.getMessage();
} finally {
try {
actionReopen();
} catch (Exception e) {
e.printStackTrace();
errMsg = "FAILED: " + e.getMessage();
}
}
if (errMsg != null) {
errorMsg(errMsg);
} else if (deleted == 0) {
infoMsg("No files were deleted.");
}
}
/** Recursively remove files and directories including the indicated
* root file.
* @param f root file name
* @return true if successful, false otherwise. Note that if the result
* is false the tree may have been partially removed.
*/
public boolean removeFile(File f) {
System.out.println("remove " + f);
if (!f.isDirectory()) return f.delete();
File[] files = f.listFiles();
boolean res = true;
if (files != null) {
for (int i = 0; i < files.length; i++) {
res = res && removeFile(files[i]);
}
}
res = res && f.delete();
return res;
}
public void actionExport() {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
Object dialog = addComponent(this, "/xml/export.xml", null, null);
}
public void export(final Object dialog) {
Object ckOver = find(dialog, "ckOver");
Object ckGzip = find(dialog, "ckGzip");
Object path = find(dialog, "path");
Object ckRanges = find(dialog, "ckRanges");
Object list = find(dialog, "ranges");
String fileName = getString(path, "text");
fileName = fileName.trim();
if (fileName.length() == 0) {
errorMsg("No output file set.");
return;
}
boolean over = getBoolean(ckOver, "selected");
boolean gzip = getBoolean(ckGzip, "selected");
if (gzip && !fileName.endsWith(".gz")) {
fileName = fileName + ".gz";
setString(path, "text", fileName);
}
File out = new File(fileName);
if (out.exists()) {
if (out.isDirectory()) {
errorMsg("Output already exists and is a directory.");
return;
}
if (!over) {
errorMsg("Output already exists.");
return;
}
}
Ranges ranges = null;
if (getBoolean(ckRanges, "selected")) {
String rs = getString(list, "text");
if (rs.trim().length() > 0) {
try {
ranges = Ranges.parse(rs);
} catch (Exception e) {
errorMsg(e.toString());
return;
}
}
}
final Object progressBar = find(dialog, "bar");
final Object counter = find(dialog, "counter");
final Object msg = find(dialog, "msg");
Observer obs = new Observer() {
public void update(Observable o, Object arg) {
ProgressNotification pn = (ProgressNotification)arg;
setInteger(progressBar, "minimum", pn.minValue);
setInteger(progressBar, "maximum", pn.maxValue);
setInteger(progressBar, "value", pn.curValue);
setString(msg, "text", pn.message);
if (!pn.aborted) {
setString(counter, "text", pn.curValue + " of " + pn.maxValue + " done.");
} else {
setString(counter, "text", "ABORTED at " + pn.curValue + " of " + pn.maxValue);
}
}
};
// toggle buttons
setBoolean(find(dialog, "startButton"), "visible", false);
setBoolean(find(dialog, "abortButton"), "visible", true);
setBoolean(find(dialog, "closeButton"), "enabled", false);
try {
_runExport(out, gzip, obs, dialog, ranges);
} catch (IOException ioe) {
errorMsg("Export failed: " + ioe.toString());
}
}
XMLExporter exporter = null;
public void _runExport(final File out, final boolean gzip, Observer obs,
final Object dialog, final Ranges ranges) throws IOException {
exporter = new XMLExporter(ir, pName, decoders);
exporter.addObserver(obs);
Thread t = new Thread() {
public void run() {
OutputStream os = null;
try {
os = new FileOutputStream(out);
if (gzip) {
os = new GZIPOutputStream(os);
}
exporter.export(os, true, true, true, "index", ranges);
exporter = null;
} catch (Exception e) {
e.printStackTrace();
errorMsg("ERROR occurred, file may be incomplete: " + e.toString());
} finally {
setBoolean(find(dialog, "startButton"), "visible", true);
setBoolean(find(dialog, "abortButton"), "visible", false);
setBoolean(find(dialog, "closeButton"), "enabled", true);
if (os != null) {
try {
os.flush();
os.close();
} catch (Exception e) {
errorMsg("ERROR closing output, file may be incomplete: " + e.toString());
}
}
}
}
};
t.start();
}
public void abortExport(Object dialog) {
if (exporter != null && exporter.isRunning()) {
exporter.abort();
}
}
/**
* Optimize the current index
* @param method Thinlet menuitem widget containing the choice of index format.
* If the widget name is "optCompound" then the index will be optimized into compound
* format; otherwise a plain multi-file format will be used.
* <p>NOTE: this method is usually invoked from the GUI, and it also re-initializes GUI
* and plugins.</p>
*/
public void actionOptimize() {
if (dir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (readOnly) {
showStatus(MSG_READONLY);
return;
}
Object dialog = addComponent(null, "/xml/optimize.xml", null, null);
setString(find(dialog, "dirName"), "text", pName);
add(dialog);
}
/**
* Optimize the index.
*/
public void optimize(final Object dialog) {
Thread t = new Thread() {
public void run() {
IndexWriter iw = null;
Object optimizeButton = find(dialog, "optimizeButton");
setBoolean(optimizeButton, "enabled", false);
Object closeButton = find(dialog, "closeButton");
setBoolean(closeButton, "enabled", false);
Object msg = find(dialog, "msg");
Object stat = find(dialog, "stat");
setString(stat, "text", "Running ...");
PanelPrintWriter ppw = new PanelPrintWriter(Luke.this, msg);
boolean useCompound = getBoolean(find(dialog, "optCompound"), "selected");
boolean expunge = getBoolean(find(dialog, "optExpunge"), "selected");
boolean keep = getBoolean(find(dialog, "optKeepAll"), "selected");
boolean useLast = getBoolean(find(dialog, "optLastCommit"), "selected");
Object tiiSpin = find(dialog, "tii");
Object segnumSpin = find(dialog, "segnum");
int tii = Integer.parseInt(getString(tiiSpin, "text"));
int segnum = Integer.parseInt(getString(segnumSpin, "text"));
try {
if (is != null) is = null;
if (ir != null) ir.close();
if (ar != null) ar.close();
IndexDeletionPolicy policy;
if (keep) {
policy = new KeepAllIndexDeletionPolicy();
} else {
policy = new KeepLastIndexDeletionPolicy();
}
IndexWriterConfig cfg = new IndexWriterConfig(LV, new WhitespaceAnalyzer());
if (!useLast) {
IndexCommit ic = ((DirectoryReader)ir).getIndexCommit();
if (ic != null) {
cfg.setIndexCommit(ic);
}
}
cfg.setIndexDeletionPolicy(policy);
cfg.setTermIndexInterval(tii);
MergePolicy p = cfg.getMergePolicy();
if (p instanceof LogMergePolicy) {
((LogMergePolicy)p).setNoCFSRatio(useCompound?1.0:0.0);
if (useCompound) {
((LogMergePolicy)p).setNoCFSRatio(1.0);
}
} else if (p instanceof TieredMergePolicy) {
((TieredMergePolicy)p).setNoCFSRatio(useCompound?1.0:0.0);
if (useCompound) {
((TieredMergePolicy)p).setNoCFSRatio(1.0);
}
}
cfg.setInfoStream(ppw);
iw = new IndexWriter(dir, cfg);
long startSize = Util.calcTotalFileSize(pName, dir);
long startTime = System.currentTimeMillis();
if (expunge) {
iw.forceMergeDeletes();
} else {
if (segnum > 1) {
iw.forceMerge(segnum, true);
} else {
iw.forceMerge(1, true);
}
}
iw.commit();
long endTime = System.currentTimeMillis();
long endSize = Util.calcTotalFileSize(pName, dir);
long deltaSize = startSize - endSize;
String sign = deltaSize < 0 ? " Increased " : " Reduced ";
String sizeMsg = sign + Util.normalizeSize(Math.abs(deltaSize)) + Util.normalizeUnit(Math.abs(deltaSize));
String timeMsg = String.valueOf(endTime - startTime) + " ms";
showStatus(sizeMsg + " in " + timeMsg);
iw.close();
setString(stat, "text", "Finished OK.");
} catch (Exception e) {
e.printStackTrace(ppw);
setString(stat, "text", "ERROR - aborted.");
errorMsg("ERROR optimizing: " + e.toString());
if (iw != null) try {
iw.close();
} catch (Exception e1) {}
} finally {
setBoolean(closeButton, "enabled", true);
}
try {
actionReopen();
is = new IndexSearcher(ir);
// add dialog again
add(dialog);
} catch (Exception e) {
e.printStackTrace(ppw);
errorMsg("ERROR reopening after optimize:\n" + e.getMessage());
}
}
};
t.start();
}
public void showPrevDoc(Object docNum) {
_showDoc(docNum, -1);
}
public void showNextDoc(Object docNum) {
_showDoc(docNum, +1);
}
public void showDoc(Object docNum) {
_showDoc(docNum, 0);
}
Document doc = null;
int iNum;
private void _showDoc(Object docNum, int incr) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
String num = getString(docNum, "text");
if (num.trim().equals("")) num = String.valueOf(-incr);
try {
iNum = Integer.parseInt(num);
iNum += incr;
if (iNum < 0 || iNum >= ir.maxDoc()) {
showStatus("Document number outside valid range.");
return;
}
setString(docNum, "text", String.valueOf(iNum));
org.apache.lucene.util.Bits live = ar.getLiveDocs();
if (live == null || live.get(iNum)) {
SlowThread st = new SlowThread(this) {
public void execute() {
try {
doc = ir.document(iNum);
_showDocFields(iNum, doc);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
} else {
showStatus("Deleted document - not available.");
_showDocFields(iNum, null);
}
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
public void actionAddDocument(Object docTable) {
if (ir == null) {
errorMsg(MSG_NOINDEX);
return;
}
Object dialog = addComponent(null, "/xml/editdoc.xml", null, null);
remove(find(dialog, "bDelAdd"));
Object cbAnalyzers = find(dialog, "cbAnalyzers");
populateAnalyzers(cbAnalyzers);
setInteger(cbAnalyzers, "selected", 0);
add(dialog);
}
public void actionReconstruct(Object docNumText) {
final int[] nums = new int[1];
try {
String numString = getString(docNumText, "text");
nums[0] = Integer.parseInt(numString);
} catch (Exception e) {
showStatus("ERROR: no valid document selected");
return;
}
final Progress progress = new Progress(this);
progress.setMessage("Reconstructing ...");
progress.show();
Thread thr = new Thread() {
public void run() {
try {
int docNum = nums[0];
DocReconstructor recon = new DocReconstructor(ir, idxFields, numTerms);
recon.addObserver(progress);
Reconstructed doc = recon.reconstruct(docNum);
Object dialog = addComponent(null, "/xml/editdoc.xml", null, null);
putProperty(dialog, "docNum", new Integer(docNum));
Object cbAnalyzers = find(dialog, "cbAnalyzers");
populateAnalyzers(cbAnalyzers);
setInteger(cbAnalyzers, "selected", 0);
Object editTabs = find(dialog, "editTabs");
setString(find(dialog, "docNum"), "text", "Fields of Doc #: " + docNum);
for (int p = 0; p < idxFields.length; p++) {
String key = idxFields[p];
if (!doc.hasField(key)) continue;
IndexableField[] fields = doc.getStoredFields().get(key);
GrowableStringArray recField = doc.getReconstructedFields().get(key);
int count = 0;
if (recField != null) count = 1;
if (fields != null && fields.length > count) count = fields.length;
for (int i = 0; i < count; i++) {
if (i > 0) recField = null; // show it only for the first field
Object tab = create("tab");
setString(tab, "text", key);
setFont(tab, getFont().deriveFont(Font.BOLD));
add(editTabs, tab);
Object editfield = addComponent(tab, "/xml/editfield.xml", null, null);
Object fType = find(editfield, "fType");
Object sText = find(editfield, "sText");
Object rText = find(editfield, "rText");
Object fBoost = find(editfield, "fBoost");
Object cbStored = find(editfield, "cbStored");
//Object cbCmp = find(editfield, "cbCmp");
Object cbBin = find(editfield, "cbBin");
Object cbIndexed = find(editfield, "cbIndexed");
Object cbTokenized = find(editfield, "cbTokenized");
Object cbTVF = find(editfield, "cbTVF");
Object cbTVFp = find(editfield, "cbTVFp");
Object cbTVFo = find(editfield, "cbTVFo");
Object cbONorms = find(editfield, "cbONorms");
Object cbOTF = find(editfield, "cbOTF");
Object stored = find(editfield, "stored");
Object restored = find(editfield, "restored");
if (ar != null) {
FieldInfos fis=ar.getFieldInfos();
FieldInfo fi = fis.fieldInfo(key);
setBoolean(cbONorms, "selected", !fi.hasNorms());
}
Field f = null;
if (fields != null && fields.length > i) {
f = (Field)fields[i];
setString(fType, "text", "Original stored field content");
String text;
if (f.binaryValue() != null) {
text = Util.bytesToHex(f.binaryValue(), true);
setBoolean(cbBin, "selected", true);
} else {
text = f.stringValue();
}
setString(sText, "text", text);
setString(fBoost, "text", String.valueOf(f.boost()));
IndexableFieldType t = f.fieldType();
setBoolean(cbStored, "selected", t.stored());
// Lucene 3.0 doesn't support compressed fields
//setBoolean(cbCmp, "selected", false);
setBoolean(cbIndexed, "selected", t.indexed());
setBoolean(cbTokenized, "selected", t.tokenized());
setBoolean(cbTVF, "selected", t.storeTermVectors());
setBoolean(cbTVFp, "selected", t.storeTermVectorPositions());
setBoolean(cbTVFo, "selected", t.storeTermVectorOffsets());
// XXX omitTF needs fixing!
//setBoolean(cbOTF, "selected", f.getOmitTermFreqAndPositions());
} else {
remove(stored);
}
if (recField != null) {
String sep = " ";
if (f == null) {
setString(fType, "text", "RESTORED content ONLY - check for errors!");
setColor(fType, "foreground", Color.red);
} else {
setBoolean(rText, "editable", false);
setBoolean(rText, "border", false);
setString(restored, "text", "Tokenized (from all '" + key + "' fields)");
sep = ", ";
}
setBoolean(cbIndexed, "selected", true);
setString(fBoost, "text", String.valueOf(1.0f));
setString(rText, "text", recField.toString(sep));
} else {
remove(restored);
}
}
}
add(dialog);
getPreferredSize(editTabs);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
progress.hide();
}
};
thr.start();
}
public boolean actionEditAdd(Object editdoc) {
Document doc = new Document();
Object cbAnalyzers = find(editdoc, "cbAnalyzers");
// reuse the logic in createAnalyzer - needs a prepared srchOptTabs
Object srchTabs = find("srchOptTabs");
Object cbType = find(srchTabs, "cbType");
String clazz = getString(cbAnalyzers, "text");
setString(cbType, "text", clazz);
Analyzer a = createAnalyzer(srchTabs);
if (a == null) {
return false;
}
Object editTabs = find(editdoc, "editTabs");
Object[] tabs = getItems(editTabs);
for (int i = 0; i < tabs.length; i++) {
String name = getString(tabs[i], "text");
if (name.trim().equals("")) continue;
Object fBoost = find(tabs[i], "fBoost");
Object fText = find(tabs[i], "sText");
if (fText == null) fText = find(tabs[i], "rText");
Object cbStored = find(tabs[i], "cbStored");
Object cbIndexed = find(tabs[i], "cbIndexed");
Object cbTokenized = find(tabs[i], "cbTokenized");
Object cbTVF = find(tabs[i], "cbTVF");
Object cbTVFo = find(tabs[i], "cbTVFo");
Object cbTVFp = find(tabs[i], "cbTVFp");
Object cbCmp = find(tabs[i], "cbCmp");
Object cbBin = find(tabs[i], "cbBin");
Object cbONorms = find(tabs[i], "cbONorms");
Object cbOTF = find(tabs[i], "cbOTF");
String text = getString(fText, "text");
byte[] binValue;
boolean binary = getBoolean(cbBin, "selected");
FieldType ft = new FieldType();
if (getBoolean(cbTVF, "selected")) {
ft.setStoreTermVectors(true);
if (getBoolean(cbTVFo, "selected")) {
ft.setStoreTermVectorOffsets(true);
}
if (getBoolean(cbTVFp, "selected")) {
ft.setStoreTermVectorPositions(true);
}
} else {
ft.setStoreTermVectors(false);
}
// XXX omitTF needs fixing
// f.setOmitTermFreqAndPositions(getBoolean(cbOTF, "selected"));
if (getBoolean(cbOTF, "selected")) {
ft.setIndexOptions(IndexOptions.DOCS_ONLY);
} else {
ft.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS);
}
ft.setStored(getBoolean(cbStored, "selected"));
ft.setIndexed(getBoolean(cbIndexed, "selected"));
ft.setTokenized(getBoolean(cbTokenized, "selected"));
if (ft.stored() == false && ft.indexed() == false) {
errorMsg("Field '" + name + "' is neither stored nor indexed.");
return false;
}
ft.setOmitNorms(getBoolean(cbONorms, "selected"));
Field f;
if (binary) {
try {
binValue = Util.hexToBytes(text);
} catch (Throwable e) {
errorMsg("Field '" + name + "': " + e.getMessage());
return false;
}
f = new Field(name, binValue, 0, binValue.length, ft);
} else {
f = new Field(name, text, ft);
}
String boostS = getString(fBoost, "text").trim();
if (!boostS.equals("") && !boostS.equals("1.0")) {
float boost = 1.0f;
try {
boost = Float.parseFloat(boostS);
} catch (Exception e) {
e.printStackTrace();
}
f.setBoost(boost);
}
doc.add(f);
}
IndexWriter writer = null;
boolean res = false;
String msg = null;
try {
ir.close();
if (ar != null) {
ar.close();
}
writer = createIndexWriter();
writer.addDocument(doc);
res = true;
} catch (Exception e) {
e.printStackTrace();
msg = "FAILED: " + e.getMessage();
res = false;
} finally {
try {
if (writer != null) writer.close();
} catch (Exception e) {
e.printStackTrace();
res = false;
msg = "FAILED: " + e.getMessage();
}
remove(editdoc);
try {
actionReopen();
// show Documents tab
Object tabpane = find("maintpane");
setInteger(tabpane, "selected", 1);
} catch (Exception e) {
e.printStackTrace();
res = false;
msg = "FAILED: " + e.getMessage();
}
}
if (!res) {
errorMsg(msg);
}
return res;
}
public void actionEditAddField(Object editdoc) {
String name = getString(find(editdoc, "fNewName"), "text");
if (name.trim().equals("")) {
showStatus("FAILED: Field name is required.");
return;
}
name = name.trim();
Object editTabs = find(editdoc, "editTabs");
Object tab = create("tab");
setString(tab, "text", name);
setFont(tab, getFont().deriveFont(Font.BOLD));
add(editTabs, tab);
addComponent(tab, "/xml/editfield.xml", null, null);
repaint(editTabs);
}
public void actionEditDeleteField(Object editfield) {
Object tab = getParent(editfield);
remove(tab);
}
/** More Like this query from the current doc (or selected fields) */
public void actionMLT(Object docNum, Object docTable) {
if (ir == null) {
errorMsg(MSG_NOINDEX);
return;
}
int id = 0;
try {
id = Integer.parseInt(getString(docNum, "text"));
} catch (NumberFormatException nfe) {
errorMsg("Invalid document number");
return;
}
MoreLikeThis mlt = new MoreLikeThis(ir);
try {
mlt.setFieldNames((String[])Util.fieldNames(ir, true).toArray(new String[0]));
} catch (Exception e) {
errorMsg("Exception collecting field names: " + e.toString());
return;
}
mlt.setMinTermFreq(1);
mlt.setMaxQueryTerms(50);
Analyzer a = createAnalyzer(find("srchOptTabs"));
if (a == null) {
return;
}
mlt.setAnalyzer(a);
Object[] rows = getSelectedItems(docTable);
BooleanQuery similar = null;
if (rows != null && rows.length > 0) {
// collect text from fields
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rows.length; i++) {
Field f = (Field)getProperty(rows[i], "field");
if (f == null) {
continue;
}
String s = f.stringValue();
if (s == null || s.trim().length() == 0) {
continue;
}
if (sb.length() > 0) sb.append(" ");
sb.append(s);
}
try {
similar = (BooleanQuery)mlt.like("field", new StringReader(sb.toString()));
} catch (Exception e) {
e.printStackTrace();
errorMsg("FAILED: " + e.getMessage());
return;
}
} else {
try {
similar = (BooleanQuery)mlt.like(id);
} catch (Exception e) {
e.printStackTrace();
errorMsg("FAILED: " + e.getMessage());
return;
}
}
if (similar.clauses() != null && similar.clauses().size() > 0) {
//System.err.println("SIMILAR: " + similar);
Object tabpane = find("maintpane");
setInteger(tabpane, "selected", 2);
Object qField = find("qField");
setString(qField, "text", similar.toString());
} else {
showStatus("WARN: empty query - check Analyzer settings");
}
}
private void _showDocFields(int docid, Document doc) {
Object table = find("docTable");
Object srchOpts = find("srchOptTabs");
Similarity sim = createSimilarity(srchOpts);
if (sim == null || !(sim instanceof TFIDFSimilarity)) {
sim = defaultSimilarity;
}
setString(find("docNum"), "text", String.valueOf(docid));
removeAll(table);
putProperty(table, "doc", doc);
putProperty(table, "docNum", new Integer(docid));
if (doc == null) {
setString(find("docNum1"), "text", String.valueOf(docid) + " DELETED");
return;
}
setString(find("docNum1"), "text", String.valueOf(docid));
for (int i = 0; i < idxFields.length; i++) {
IndexableField[] fields = doc.getFields(idxFields[i]);
if (fields.length == 0) {
addFieldRow(table, idxFields[i], null, docid, null);
continue;
}
for (int j = 0; j < fields.length; j++) {
addFieldRow(table, idxFields[i], fields[j], docid, (TFIDFSimilarity)sim);
}
}
doLayout(table);
}
Font courier = null;
private void addFieldRow(Object table, String fName, IndexableField ixf, int docid, TFIDFSimilarity sim) {
Object row = create("row");
add(table, row);
putProperty(row, "field", ixf);
putProperty(row, "fName", fName);
Object cell = create("cell");
setString(cell, "text", fName );
add(row, cell);
cell = create("cell");
Field f = (Field)ixf;
String flags = Util.fieldFlags(f, infos.fieldInfo(fName));
boolean hasVectors = false;
try {
hasVectors = ar.getTermVector(docid, fName) != null;
} catch (Exception e) {
// ignore
}
// consider skipping this field altogether?
if (ixf == null && !hasVectors) {
setBoolean(cell, "enabled", false);
}
if (hasVectors) {
flags = flags.substring(0, 7) + "V" + flags.substring(8);
}
setString(cell, "text", flags);
setFont(cell, "font", courier);
setChoice(cell, "alignment", "center");
add(row, cell);
cell = create("cell");
FieldInfo info = infos.fieldInfo(fName);
if (f != null) {
try {
if (ar != null && info.hasNorms()) {
NumericDocValues norms = ar.getNormValues(fName);
String val = Util.normsToString(norms, fName, docid, sim);
setString(cell, "text", val);
} else {
setString(cell, "text", "---");
setBoolean(cell, "enabled", false);
}
} catch (IOException ioe) {
ioe.printStackTrace();
setString(cell, "text", "!?!");
}
} else {
setString(cell, "text", "---");
setBoolean(cell, "enabled", false);
}
add(row, cell);
cell = create("cell");
if (f != null) {
String text = f.stringValue();
if (text == null) {
if (f.binaryValue() != null) {
text = Util.bytesToHex(f.binaryValue(), false);
} else {
text = "(null)";
}
}
Decoder dec = decoders.get(f.name());
if (dec == null) dec = defDecoder;
try {
if (f.fieldType().stored()/* && f.numericValue() == null && f.binaryValue() == null*/) {
text = dec.decodeStored(f.name(), f);
} else {
text = dec.decodeTerm(f.name(), text);
}
} catch (Throwable e) {
setColor(cell, "foreground", Color.RED);
}
setString(cell, "text", Util.escape(text));
} else {
setString(cell, "text", "<not present or not stored>");
setBoolean(cell, "enabled", false);
}
add(row, cell);
}
public void showTV(Object table) {
final Object row = getSelectedItem(table);
if (row == null) return;
if (ar == null) {
showStatus(MSG_NOINDEX);
return;
}
final Integer DocId = (Integer) getProperty(table, "docNum");
if (DocId == null) {
showStatus("Missing Doc. Id.");
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
String fName = (String) getProperty(row, "fName");
Terms tfv = ar.getTermVector(DocId.intValue(), fName);
if (tfv == null) {
showStatus("Term Vector not available in field " + fName + " for this doc.");
return;
}
List<IntPair> tvs = TermVectorMapper.map(tfv, null, true, false);
if (tvs == null || tvs.isEmpty()) {
showStatus("Term Vector not available (empty).");
return;
}
Object dialog = addComponent(null, "/xml/vector.xml", null, null);
setString(find(dialog, "fld"), "text", fName);
Object vTable = find(dialog, "vTable");
Decoder dec = decoders.get(fName);
if (dec == null) dec = defDecoder;
Collections.sort(tvs, new IntPair.PairComparator(false, true));
for (int i = 0; i < tvs.size(); i++) {
Object r = create("row");
add(vTable, r);
IntPair ip = tvs.get(i);
putProperty(r, "tf", ip);
Object cell = create("cell");
String s;
try {
s = dec.decodeTerm(fName, ip.text);
} catch (Throwable e) {
s = ip.text;
setColor(cell, "foreground", Color.RED);
}
setString(cell, "text", Util.escape(s));
add(r, cell);
cell = create("cell");
setString(cell, "text", String.valueOf(ip.cnt));
add(r, cell);
cell = create("cell");
if (ip.positions != null) {
StringBuilder sb = new StringBuilder();
for (int k = 0; k < ip.positions.length; k++) {
if (k > 0) sb.append(',');
sb.append(String.valueOf(ip.positions[k]));
}
setString(cell, "text", sb.toString());
}
add(r, cell);
cell = create("cell");
if (ip.starts != null) {
StringBuilder sb = new StringBuilder();
for (int k = 0; k < ip.starts.length; k++) {
if (k > 0) sb.append(',');
sb.append(ip.starts[k] + "-" + ip.ends[k]);
}
setString(cell, "text", sb.toString());
}
add(r, cell);
}
add(dialog);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void clipTV(Object vTable) {
Object[] rows = getItems(vTable);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rows.length; i++) {
IntPair tf = (IntPair)getProperty(rows[i], "tf");
sb.append(tf.cnt + "\t" + tf.text);
if (tf.positions != null) {
sb.append("\t");
for (int k = 0; k < tf.positions.length; k++) {
if (k > 0) sb.append(',');
sb.append(String.valueOf(tf.positions[k]));
}
}
if (tf.starts != null) {
if (tf.positions == null) sb.append("\t");
sb.append("\t");
for (int k = 0; k < tf.starts.length; k++) {
if (k > 0) sb.append(',');
sb.append(tf.starts[i] + "-" + tf.ends[i]);
}
}
sb.append("\n");
}
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
public void actionExamineNorm(Object table) throws Exception {
Object row = getSelectedItem(table);
if (row == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
Field f = (Field) getProperty(row, "field");
if (f == null) {
showStatus("No data available for this field");
return;
}
FieldInfo info = infos.fieldInfo(f.name());
if (!info.isIndexed()) {
showStatus("Cannot examine norm value - this field is not indexed.");
return;
}
if (!info.hasNorms()) {
showStatus("Cannot examine norm value - this field has no norms.");
return;
}
Object dialog = addComponent(null, "/xml/fnorm.xml", null, null);
Integer docNum = (Integer)getProperty(table, "docNum");
putProperty(dialog, "docNum", getProperty(table, "docNum"));
putProperty(dialog, "field", f);
Object curNorm = find(dialog, "curNorm");
Object newNorm = find(dialog, "newNorm");
Object encNorm = find(dialog, "encNorm");
Object doc = find(dialog, "docNum");
Object fld = find(dialog, "fld");
Object srchOpts = find("srchOptTabs");
Similarity sim = createSimilarity(srchOpts);
TFIDFSimilarity s = null;
if (sim != null && (sim instanceof TFIDFSimilarity)) {
s = (TFIDFSimilarity)sim;
} else {
s = defaultSimilarity;
}
setString(doc, "text", String.valueOf(docNum.intValue()));
setString(fld, "text", f.name());
putProperty(dialog, "similarity", s);
if (ar != null) {
try {
NumericDocValues nnorms = ar.getNormValues(f.name());
byte curBVal=0;
if (nnorms!=null) {curBVal=(byte)nnorms.get(docNum.intValue());}
float curFVal = Util.decodeNormValue(curBVal, f.name(), s);
setString(curNorm, "text", String.valueOf(curFVal));
setString(newNorm, "text", String.valueOf(curFVal));
setString(encNorm, "text", String.valueOf(curFVal) +
" (0x" + Util.byteToHex(curBVal) + ")");
} catch (Exception e) {
e.printStackTrace();
errorMsg("Error reading norm: " + e.toString());
return;
}
}
add(dialog);
displayNewNorm(dialog);
}
public void displayNewNorm(Object dialog) {
Object newNorm = find(dialog, "newNorm");
Object encNorm = find(dialog, "encNorm");
Field f = (Field)getProperty(dialog, "field");
TFIDFSimilarity s = (TFIDFSimilarity)getProperty(dialog, "similarity");
Object sim = find(dialog, "sim");
String simClassString = getString(sim, "text");
if (simClassString != null && simClassString.trim().length() > 0
&& !simClassString.equals(defaultSimilarity.getClass().getName())) {
try {
Class cls = Class.forName(simClassString.trim());
if (TFIDFSimilarity.class.isAssignableFrom(cls)) {
s = (TFIDFSimilarity)cls.newInstance();
putProperty(dialog, "similarity", s);
}
} catch (Throwable t) {
t.printStackTrace();
showStatus("Invalid similarity class " + simClassString + ", using DefaultSimilarity.");
}
}
if (s == null) {
s = defaultSimilarity;
}
setString(sim, "text", s.getClass().getName());
try {
float newFVal = Float.parseFloat(getString(newNorm, "text"));
long newLVal = Util.encodeNormValue(newFVal, f.name(), s);
float encFVal = Util.decodeNormValue(newLVal, f.name(), s);
setString(encNorm, "text", String.valueOf(encFVal) +
" (0x" + Util.longToHex(newLVal) + ")");
putProperty(dialog, "newNorm", new Float(newFVal));
doLayout(dialog);
} catch (Exception e) {
// XXX eat silently
}
}
public void showTField(Object table) {
Object row = getSelectedItem(table);
if (row == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
Field f = (Field) getProperty(row, "field");
if (f == null) {
showStatus("No data available for this field");
return;
}
Object dialog = addComponent(null, "/xml/field.xml", null, null);
Object fName = find(dialog, "fld");
putProperty(dialog, "f", f);
setString(fName, "text", f.name());
add(dialog);
_showData(dialog);
}
public void _showData(Object dialog) {
Object fDataText = find(dialog, "fDataText");
Field f = (Field)getProperty(dialog, "f");
String value = null;
String enc = "cbUtf";
Object choice = getSelectedItem(find(dialog, "cbData"));
String selEnc = getString(choice, "name");
boolean warn = false;
if (selEnc != null) enc = selEnc;
int len = 0;
byte[] data = null;
if (f.binaryValue() != null) {
BytesRef bytes = f.binaryValue();
data = new byte[bytes.length];
System.arraycopy(bytes.bytes, bytes.offset, data, 0,
bytes.length);
}
else if (f.stringValue() != null) {
try {
data = f.stringValue().getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
warn = true;
uee.printStackTrace();
data = f.stringValue().getBytes();
}
}
if (data == null) data = new byte[0];
if (enc.equals("cbHex")) {
setString(find(dialog, "unit"), "text", " bytes");
value = Util.bytesToHex(data, 0, data.length, true);
len = data.length;
} else if (enc.equals("cbUtf")) {
setString(find(dialog, "unit"), "text", " UTF-8 characters");
value = f.stringValue();
if (value != null) len = value.length();
} else if (enc.equals("cbDef")) {
setString(find(dialog, "unit"), "text", " characters");
value = new String(data);
len = value.length();
} else if (enc.equals("cbDate")) {
try {
Date d = DateTools.stringToDate(f.stringValue());
value = d.toString();
len = 1;
} catch (Exception e) {
warn = true;
value = Util.bytesToHex(data, 0, data.length, true);
}
} else if (enc.equals("cbLong")) {
try {
long num = NumericUtils.prefixCodedToLong(new BytesRef(f.stringValue()));
value = String.valueOf(num);
len = 1;
} catch (Exception e) {
warn = true;
value = Util.bytesToHex(data, 0, data.length, true);
}
} else if (enc.equals("cbNum")) {
if (f.numericValue() != null) {
value = f.numericValue().toString() + " (" + f.numericValue().getClass().getSimpleName() + ")";
} else {
warn = true;
value = Util.bytesToHex(data, 0, data.length, true);
}
} else if (enc.equals("cbInt")) {
if (data.length % 4 == 0) {
setString(find(dialog, "unit"), "text", " int values");
len = data.length / 4;
StringBuilder sb = new StringBuilder();
for (int k = 0; k < data.length; k += 4) {
if (k > 0) sb.append(',');
sb.append(String.valueOf(PayloadHelper.decodeInt(data, k)));
}
value = sb.toString();
} else {
warn = true;
value = Util.bytesToHex(data, 0, data.length, true);
}
} else if (enc.equals("cbFloat")) {
if (data.length % 4 == 0) {
setString(find(dialog, "unit"), "text", " float values");
len = data.length / 4;
StringBuilder sb = new StringBuilder();
for (int k = 0; k < data.length; k += 4) {
if (k > 0) sb.append(',');
sb.append(String.valueOf(PayloadHelper.decodeFloat(data, k)));
}
value = sb.toString();
} else {
warn = true;
value = Util.bytesToHex(data, 0, data.length, true);
}
}
setString(fDataText, "text", value);
setString(find(dialog, "len"), "text", String.valueOf(len));
if (warn) {
setBoolean(fDataText, "enabled", false);
errorMsg(MSG_CONV_ERROR);
} else {
setBoolean(fDataText, "enabled", true);
}
}
public void saveField(Object table) {
Object row = getSelectedItem(table);
if (row == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
Field f = (Field) getProperty(row, "field");
if (f == null) {
showStatus("No data available for this field");
return;
}
JFileChooser fd = new JFileChooser();
fd.setDialogType(JFileChooser.SAVE_DIALOG);
fd.setDialogTitle("Save field content to a file");
fd.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
fd.setFileHidingEnabled(false);
if (this.baseDir != null)
fd.setCurrentDirectory(new File(this.baseDir));
else fd.setCurrentDirectory(new File(System.getProperty("user.dir")));
int res = fd.showSaveDialog(this);
File iFile = null;
if (res == JFileChooser.APPROVE_OPTION) iFile = fd.getSelectedFile();
if (iFile == null) return;
if (iFile.exists() && iFile.isDirectory()) {
errorMsg("Can't overwrite a directory.");
return;
}
Object progress = null;
try {
byte[] data = null;
if (f.binaryValue() != null) {
BytesRef bytes = f.binaryValue();
data = new byte[bytes.length];
System.arraycopy(bytes.bytes, bytes.offset, data, 0,
bytes.length);
}
else {
try {
data = f.stringValue().getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
uee.printStackTrace();
errorMsg(uee.toString());
data = f.stringValue().getBytes();
}
}
if (data == null || data.length == 0) {
showStatus("No data available");
return;
}
progress = addComponent(null, "/xml/progress.xml", null, null);
setString(find(progress, "msg"), "text", "Saving...");
Object bar = find(progress, "bar");
setInteger(bar, "maximum", 100);
OutputStream os = new FileOutputStream(iFile);
int delta = data.length / 100;
if (delta == 0) delta = 1;
add(progress);
for (int i = 0; i < data.length; i++) {
os.write(data[i]);
if (i % delta == 0) {
setInteger(bar, "value", i / delta);
}
}
os.flush();
os.close();
setString(find(progress, "msg"), "text", "Done!");
try { Thread.sleep(1000); } catch (Exception e) {};
} catch (IOException ioe) {
ioe.printStackTrace();
errorMsg("Can't save: " + ioe);
return;
} finally {
if (progress != null) remove(progress);
}
}
public void clipCopyFields(Object table) {
Object[] rows = getSelectedItems(table);
if (rows == null || rows.length == 0) return;
Document doc = (Document) getProperty(table, "doc");
if (doc == null) return;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < rows.length; i++) {
Field f = (Field) getProperty(rows[i], "field");
if (f == null) continue;
if (i > 0) sb.append('\n');
sb.append(f.toString());
}
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
public void clipCopyDoc(Object table) {
Document doc = (Document) getProperty(table, "doc");
if (doc == null) return;
StringBuffer sb = new StringBuffer();
Object[] rows = getItems(table);
for (int i = 0; i < rows.length; i++) {
Field f = (Field) getProperty(rows[i], "field");
if (f == null) continue;
if (i > 0) sb.append('\n');
sb.append(f.toString());
}
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
public void showFirstTerm(final Object fCombo, final Object fText) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
String fld = getString(fCombo, "text");
Terms terms = MultiFields.getTerms(ir, fld);
TermsEnum te = terms.iterator(null);
putProperty(fCombo, "te", te);
putProperty(fCombo, "teField", fld);
BytesRef term = te.next();
_showTerm(fCombo, fText, new Term(fld, term));
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void showNextTerm(final Object fCombo, final Object fText) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
String text;
text = getString(fText, "text");
if (text == null || text.trim().equals("")) text = "";
if (text.length() == 0) {
showFirstTerm(fCombo, fText);
return;
}
TermsEnum te = (TermsEnum)getProperty(fCombo, "te");
String fld = getString(fCombo, "text");
String teField = (String)getProperty(fCombo, "teField");
SeekStatus status;
BytesRef rawTerm = null;
if (te != null) {
rawTerm = te.term();
}
String rawString = rawTerm != null ? rawTerm.utf8ToString() : null;
if (te == null || !teField.equals(fld) || !text.equals(rawString)) {
Terms terms = MultiFields.getTerms(ir, fld);
te = terms.iterator(null);
putProperty(fCombo, "te", te);
putProperty(fCombo, "teField", fld);
status = te.seekCeil(new BytesRef(text));
if (status.equals(SeekStatus.FOUND)) {
rawTerm = te.term();
} else {
rawTerm = null;
}
} else {
rawTerm = te.next();
}
if (rawTerm == null) { // proceed to next field
int idx = fn.indexOf(fld);
while (idx < fn.size() - 1) {
idx++;
setInteger(fCombo, "selected", idx);
fld = fn.get(idx);
Terms terms = MultiFields.getTerms(ir, fld);
if (terms == null) {
continue;
}
te = terms.iterator(null);
rawTerm = te.next();
putProperty(fCombo, "te", te);
putProperty(fCombo, "teField", fld);
break;
}
}
if (rawTerm == null) {
showStatus("No more terms");
return;
}
//Term t = new Term(fld, term.utf8ToString());
_showTerm(fCombo, fText, new Term(fld, rawTerm));
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void showTerm(final Object fCombo, final Object fText) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
String text;
Term rawTerm = (Term)getProperty(fText, "term");
text = getString(fText, "text");
if (rawTerm != null) {
String s = (String)getProperty(fText, "decText");
if (s.equals(text)) {
text = rawTerm.text();
}
}
String fld = getString(fCombo, "text");
if (text == null || text.trim().equals("")) return;
Term t = new Term(fld, text);
if (ir.docFreq(t) == 0) { // missing term
Terms terms = MultiFields.getTerms(ir, fld);
TermsEnum te = terms.iterator(null);
te.seekCeil(new BytesRef(text));
t = new Term(fld, te.term().utf8ToString());
}
_showTerm(fCombo, fText, t);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
private void _showTerm(Object fCombo, Object fText, final Term t) {
if (t == null) {
showStatus("No terms?!");
return;
}
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
Object[] choices = getItems(fCombo);
for (int i = 0; i < choices.length; i++) {
if (t.field().equals(getString(choices[i], "text"))) {
setInteger(fCombo, "selected", i);
break;
}
}
Decoder dec = decoders.get(t.field());
if (dec == null) dec = defDecoder;
String s = null;
boolean decodeErr = false;
try {
s = dec.decodeTerm(t.field(), t.text());
} catch (Throwable e) {
s = e.getMessage();
decodeErr = true;
}
setString(fText, "text", t.text());
Object rawText = find("decText");
if (!s.equals(t.text())) {
setString(rawText, "text", s);
if (decodeErr) {
setColor(rawText, "foreground", Color.RED);
} else {
setColor(rawText, "foreground", Color.BLUE);
}
} else {
setString(rawText, "text", "");
setColor(rawText, "foreground", Color.BLACK);
}
putProperty(fText, "term", t);
putProperty(fText, "decText", s);
putProperty(fText, "td", null);
setString(find("tdNum"), "text", "?");
setString(find("tFreq"), "text", "?");
SlowThread st = new SlowThread(this) {
public void execute() {
Object dFreq = find("dFreq");
try {
int freq = ir.docFreq(t);
setString(dFreq, "text", String.valueOf(freq));
dFreq = find("tdMax");
setString(dFreq, "text", String.valueOf(freq));
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
setString(dFreq, "text", "?");
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void showFirstTermDoc(final Object fText) {
final Term t = (Term) getProperty(fText, "term");
if (t == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (ar == null) {
errorMsg(MSG_LUCENE3828);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
//DocsEnum td = ar.termDocsEnum(ar.getLiveDocs(), t.field(), new BytesRef(t.text()), 0);
DocsEnum td = ar.termDocsEnum(t);
if (td == null) {
showStatus("No such term: " + t);
return;
}
if (td.nextDoc() == DocsEnum.NO_MORE_DOCS) {
showStatus("No documents with this term: " + t + " (NO_MORE_DOCS)");
return;
}
setString(find("tdNum"), "text", "1");
putProperty(fText, "td", td);
_showTermDoc(fText, td);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void showNextTermDoc(final Object fText) {
final Term t = (Term) getProperty(fText, "term");
if (t == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
DocsEnum td = (DocsEnum) getProperty(fText, "td");
if (td == null) {
showFirstTermDoc(fText);
return;
}
if (td.nextDoc() == DocsEnum.NO_MORE_DOCS) {
showStatus("No more docs for this term");
return;
}
Object tdNum = find("tdNum");
String sCnt = getString(tdNum, "text");
int cnt = 1;
try {
cnt = Integer.parseInt(sCnt);
} catch (Exception e) {}
;
setString(tdNum, "text", String.valueOf(cnt + 1));
_showTermDoc(fText, td);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void showPositions(final Object fText) {
final Term t = (Term) getProperty(fText, "term");
if (t == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (ar == null) {
errorMsg(MSG_LUCENE3828);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
FieldInfo fi = infos.fieldInfo(t.field());
boolean withOffsets = false;
if (fi != null) {
IndexOptions opts = fi.getIndexOptions();
if (opts != null) {
if (opts.equals(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS)) {
withOffsets = true;
}
}
}
DocsEnum tdd = (DocsEnum)getProperty(fText, "td");
if (tdd == null) {
showStatus("Unknown document number.");
return;
}
int flags = DocsAndPositionsEnum.FLAG_PAYLOADS;
if (withOffsets) {
flags |= DocsAndPositionsEnum.FLAG_OFFSETS;
}
//DocsAndPositionsEnum td = ar.termPositionsEnum(ar.getLiveDocs(), t.field(), t.bytes(), flags);
DocsAndPositionsEnum td = ar.termPositionsEnum(t);
if (td == null) {
showStatus("No position information available for this term.");
return;
}
if (td.advance(tdd.docID()) != td.docID()) {
showStatus("No position available for this doc and this term.");
return;
}
Object dialog = addComponent(null, "/xml/positions.xml", null, null);
setString(find(dialog, "term"), "text", t.toString());
String docNum = getString(find("docNum"), "text");
setString(find(dialog, "docNum"), "text", docNum);
setString(find(dialog, "freq"), "text", String.valueOf(td.freq()));
setString(find(dialog, "offs"), "text", String.valueOf(withOffsets));
putProperty(dialog, "td", td);
Object pTable = find(dialog, "pTable");
removeAll(pTable);
int freq = td.freq();
for (int i = 0; i < freq; i++) {
try {
int pos = td.nextPosition();
Object r = create("row");
Object cell = create("cell");
setString(cell, "text", String.valueOf(pos));
add(r, cell);
cell = create("cell");
add(r, cell);
if (withOffsets) {
setString(cell, "text", td.startOffset() + "-" + td.endOffset());
} else {
setString(cell, "text", "---");
setBoolean(cell, "enabled", false);
}
cell = create("cell");
add(r, cell);
BytesRef payload = td.getPayload();
if (payload!=null) {
putProperty(r, "payload", (BytesRef)payload.clone());
}
add(pTable, r);
} catch (IOException ioe) {
errorMsg("Error: " + ioe.toString());
return;
}
}
_showPayloads(dialog);
add(dialog);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void _showPayloads(Object dialog) {
Object cbPay = find(dialog, "cbPay");
Object choice = getSelectedItem(cbPay);
String enc = "cbUtf";
if (choice != null) enc = getString(choice, "name");
Object pTable = find(dialog, "pTable");
Object[] rows = getItems(pTable);
boolean warn = false;
for (int i = 0; i < rows.length; i++) {
BytesRef payload = (BytesRef)getProperty(rows[i], "payload");
if (payload == null) continue;
Object cell = getItem(rows[i], 2);
String curEnc = enc;
if (enc.equals("cbInt") || enc.equals("cbFloat")) {
if (payload.length % 4 != 0)
curEnc = "cbHex";
}
String val = "?";
if (curEnc.equals("cbUtf")) {
try {
val = new String(payload.bytes, payload.offset, payload.length, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
val = new String(payload.bytes, payload.offset, payload.length);
curEnc = "cbDef";
}
} else if (curEnc.equals("cbHex")) {
val = Util.bytesToHex(payload.bytes, payload.offset, payload.length, false);
} else if (curEnc.equals("cbDef")) {
val = new String(payload.bytes, payload.offset, payload.length);
} else if (curEnc.equals("cbInt")) {
StringBuilder sb = new StringBuilder();
for (int k = payload.offset; k < payload.offset + payload.length; k += 4) {
if (k > 0) sb.append(',');
sb.append(String.valueOf(PayloadHelper.decodeInt(payload.bytes, k)));
}
val = sb.toString();
} else if (curEnc.equals("cbFloat")) {
StringBuilder sb = new StringBuilder();
for (int k = payload.offset; k < payload.offset + payload.length; k += 4) {
if (k > 0) sb.append(',');
sb.append(String.valueOf(PayloadHelper.decodeFloat(payload.bytes, k)));
}
val = sb.toString();
}
setString(cell, "text", val);
if (!curEnc.equals(enc)) {
setBoolean(cell, "enabled", false);
warn = true;
} else {
setBoolean(cell, "enabled", true);
}
}
if (warn) {
errorMsg(MSG_CONV_ERROR);
}
}
public void clipPositions(Object pTable) {
Object[] rows = getItems(pTable);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < rows.length; i++) {
if (i > 0) sb.append('\n');
Object[] cells = getItems(rows[i]);
for (int k = 0; k < cells.length; k++) {
if (k > 0) sb.append('\t');
sb.append(getString(cells[k], "text"));
}
}
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
public void showAllTermDoc(Object fText) {
Term t = (Term) getProperty(fText, "term");
if (t == null) return;
if (ir == null) {
showStatus("MSG_NOINDEX");
return;
}
Object tabpane = find("maintpane");
setInteger(tabpane, "selected", 2);
Object qField = find("qField");
setString(qField, "text", t.field() + ":" + t.text());
Object qFieldParsed = find("qFieldParsed");
Object ckScoreRes = find("ckScoreRes");
Object ckOrderRes = find("ckOrderRes");
Object cntRepeat = find("cntRepeat");
final boolean scoreRes = getBoolean(ckScoreRes, "selected");
final boolean orderRes = getBoolean(ckOrderRes, "selected");
final int repeat = Integer.parseInt(getString(cntRepeat, "text"));
final Query q = new TermQuery(t);
setString(qFieldParsed, "text", q.toString());
SlowThread st = new SlowThread(this) {
public void execute() {
IndexSearcher is = null;
try {
is = new IndexSearcher(ir);
Object sTable = find("sTable");
removeAll(sTable);
AllHitsCollector ahc = new AllHitsCollector(orderRes, scoreRes);
_search(q, is, ahc, sTable, repeat);
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.getMessage());
} finally {
if (is != null) {
is = null;
}
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public Analyzer createAnalyzer(Object srchOpts) {
Analyzer res = null;
String sAType = getString(find(srchOpts, "cbType"), "text");
if (sAType.trim().equals("")) {
sAType = "org.apache.lucene.analysis.standard.StandardAnalyzer";
setString(find("cbType"), "text", sAType);
}
String arg = getString(find(srchOpts, "snoName"), "text");
if (arg == null) arg = "";
try {
Constructor zeroArg = null, zeroArgV = null, oneArg = null, oneArgV = null;
try {
zeroArgV = Class.forName(sAType).getConstructor(new Class[]{Version.class});
} catch (NoSuchMethodException e) {
zeroArgV = null;
try {
zeroArg = Class.forName(sAType).getConstructor(new Class[0]);
} catch (NoSuchMethodException e1) {
zeroArg = null;
}
}
try {
oneArgV = Class.forName(sAType).getConstructor(new Class[]{Version.class, String.class});
} catch (NoSuchMethodException e) {
oneArgV = null;
try {
oneArg = Class.forName(sAType).getConstructor(new Class[]{String.class});
} catch (NoSuchMethodException e1) {
oneArg = null;
}
}
if (arg.length() == 0) {
if (zeroArgV != null) {
res = (Analyzer)zeroArgV.newInstance(LV);
} else if (zeroArg != null) {
res = (Analyzer)zeroArg.newInstance();
} else if (oneArgV != null) {
res = (Analyzer)oneArgV.newInstance(new Object[]{LV, arg});
} else if (oneArg != null) {
res = (Analyzer)oneArg.newInstance(new Object[]{arg});
} else {
throw new Exception("Must have a zero-arg or (Version) or (Version, String) constructor");
}
} else {
if (oneArgV != null) {
res = (Analyzer)oneArgV.newInstance(new Object[]{LV, arg});
} else if (oneArg != null) {
res = (Analyzer)oneArg.newInstance(new Object[]{arg});
} else if (zeroArgV != null) {
res = (Analyzer)zeroArgV.newInstance(new Object[]{LV});
} else if (zeroArg != null) {
res = (Analyzer)zeroArg.newInstance(new Object[0]);
} else {
throw new Exception("Must have a zero-arg or (String) constructor");
}
}
} catch (Exception e) {
e.printStackTrace();
errorMsg("Analyzer '" + sAType + "' error: " + e.getMessage());
return null;
}
Prefs.setProperty(Prefs.P_ANALYZER, res.getClass().getName());
return res;
}
protected String getDefaultField(Object srchOptTabs) {
String defField = getString(find(srchOptTabs, "defFld"), "text");
if (defField == null || defField.trim().equals("")) {
if (ir != null) {
defField = idxFields[0];
setString(find(srchOptTabs, "defFld"), "text", defField);
} else {
defField = "DEFAULT";
}
}
return defField;
}
/**
* Create a Query instance that corresponds to values selected in the UI,
* such as analyzer class name and arguments, and default field.
* @return
*/
public Query createQuery(String queryString) throws Exception {
Object srchOpts = find("srchOptTabs");
Analyzer analyzer = createAnalyzer(srchOpts);
if (analyzer == null) {
return null;
}
String defField = getDefaultField(srchOpts);
QueryParser qp = new QueryParser(defField, analyzer);
Object ckXmlParser = find(srchOpts, "ckXmlParser");
Object ckWild = find(srchOpts, "ckWild");
Object ckPosIncr = find(srchOpts, "ckPosIncr");
Object ckLoExp = find(srchOpts, "ckLoExp");
Object cbDateRes = find(srchOpts, "cbDateRes");
DateTools.Resolution resolution = Util.getResolution(getString(cbDateRes, "text"));
Object cbOp = find(srchOpts, "cbOp");
Object bqMaxCount = find(srchOpts, "bqMaxCount");
int maxCount = 1024;
try {
maxCount = Integer.parseInt(getString(bqMaxCount, "text"));
} catch (Exception e) {
e.printStackTrace();
showStatus("Invalid BooleanQuery max clause count, using default 1024");
}
QueryParser.Operator op;
BooleanQuery.setMaxClauseCount(maxCount);
String opString = getString(cbOp, "text");
if (opString.equalsIgnoreCase("OR")) {
op = QueryParser.OR_OPERATOR;
} else {
op = QueryParser.AND_OPERATOR;
}
qp.setAllowLeadingWildcard(getBoolean(ckWild, "selected"));
qp.setEnablePositionIncrements(getBoolean(ckPosIncr, "selected"));
qp.setLowercaseExpandedTerms(getBoolean(ckLoExp, "selected"));
qp.setDateResolution(resolution);
qp.setDefaultOperator(op);
if (getBoolean(ckXmlParser, "selected")) {
CoreParser cp = createParser(defField,analyzer);
Query q = cp.parse(new ByteArrayInputStream(queryString.getBytes("UTF-8")));
return q;
} else {
return qp.parse(queryString);
}
}
private CoreParser createParser(String defaultField, Analyzer analyzer ) throws Exception {
if(xmlQueryParserFactoryClassName == null) {
//Use the default
return new CorePlusExtensionsParser(defaultField,analyzer);
}
//Use a user-defined parser (classname passed in -xmlQueryParserFactory command-line parameter
XmlQueryParserFactory parserFactory=(XmlQueryParserFactory) Class.forName(xmlQueryParserFactoryClassName).newInstance();
return parserFactory.createParser(defaultField,analyzer);
}
public Similarity createSimilarity(Object srchOpts) {
Object ckSimDef = find(srchOpts, "ckSimDef");
Object ckSimSweet = find(srchOpts, "ckSimSweet");
Object ckSimOther = find(srchOpts, "ckSimOther");
Object simClass = find(srchOpts, "simClass");
Object ckSimCust = find(srchOpts, "ckSimCust");
if (getBoolean(ckSimDef, "selected")) {
return new DefaultSimilarity();
} else if (getBoolean(ckSimSweet, "selected")) {
return new SweetSpotSimilarity();
} else if (getBoolean(ckSimOther, "selected")) {
try {
Class clazz = Class.forName(getString(simClass, "text"));
if (Similarity.class.isAssignableFrom(clazz)) {
Similarity sim = (Similarity)clazz.newInstance();
return sim;
} else {
throw new Exception("Not a subclass of Similarity: " + clazz.getName());
}
} catch (Exception e) {
e.printStackTrace();
showStatus("ERROR: invalid Similarity, using default");
setBoolean(ckSimDef, "selected", true);
setBoolean(ckSimOther, "selected", false);
return new DefaultSimilarity();
}
} else if (getBoolean(ckSimCust, "selected")) {
return similarity;
} else {
return new DefaultSimilarity();
}
}
public AccessibleHitCollector createCollector(Object srchOpts) throws Exception {
Object ckNormRes = find(srchOpts, "ckNormRes");
Object ckAllRes = find(srchOpts, "ckAllRes");
Object ckLimRes = find(srchOpts, "ckLimRes");
Object ckLimTime = find(srchOpts, "ckLimTime");
Object limTime = find(srchOpts, "limTime");
Object ckLimCount = find(srchOpts, "ckLimCount");
Object limCount = find(srchOpts, "limCount");
Object ckScoreRes = find(srchOpts, "ckScoreRes");
Object ckOrderRes = find(srchOpts, "ckOrderRes");
boolean scoreRes = getBoolean(ckScoreRes, "selected");
boolean orderRes = getBoolean(ckOrderRes, "selected");
Collector hc = null;
if (getBoolean(ckNormRes, "selected")) {
return new AccessibleTopHitCollector(1000, orderRes, scoreRes);
} else if (getBoolean(ckAllRes, "selected")) {
return new AllHitsCollector(orderRes, scoreRes);
} else if (getBoolean(ckLimRes, "selected")) {
// figure out the type
if (getBoolean(ckLimCount, "selected")) {
int lim = Integer.parseInt(getString(limCount, "text"));
return new CountLimitedHitCollector(lim, orderRes, scoreRes);
} else if (getBoolean(ckLimTime, "selected")) {
int lim = Integer.parseInt(getString(limTime, "text"));
return new IntervalLimitedCollector(lim, orderRes, scoreRes);
} else {
throw new Exception("Unknown LimitedHitCollector type");
}
} else {
throw new Exception("Unknown HitCollector type");
}
}
public void explainStructure(Object qTabs) {
Object qField = find("qField");
String queryS = getString(qField, "text");
if (queryS.trim().equals("")) {
showStatus("Empty query");
return;
}
showParsed();
int idx = getSelectedIndex(qTabs);
Query q = null;
if (idx == 0) {
q = (Query)getProperty(qField, "qParsed");
} else {
q = (Query)getProperty(qField, "qRewritten");
}
Object dialog = addComponent(this, "/xml/qexplain.xml", null, null);
Object tree = find(dialog, "qTree");
_explainStructure(tree, q);
}
private void _explainStructure(Object parent, Query q) {
String clazz = q.getClass().getName();
if (clazz.startsWith("org.apache.lucene.")) {
clazz = "lucene." + q.getClass().getSimpleName();
} else if (clazz.startsWith("org.apache.solr.")) {
clazz = "solr." + q.getClass().getSimpleName();
}
float boost = q.getBoost();
Object n = create("node");
add(parent, n);
String msg = clazz;
if (boost != 1.0f) {
msg += ": boost=" + df.format(boost);
}
setFont(n, getFont().deriveFont(Font.BOLD));
setString(n, "text", msg);
if (clazz.equals("lucene.TermQuery")) {
Object n1 = create("node");
Term t = ((TermQuery)q).getTerm();
setString(n1, "text", "Term: field='" + t.field() + "' text='" + t.text() + "'");
add(n, n1);
} else if (clazz.equals("lucene.BooleanQuery")) {
BooleanQuery bq = (BooleanQuery)q;
BooleanClause[] clauses = bq.getClauses();
int max = bq.getMaxClauseCount();
Object n1 = create("node");
String descr = "clauses=" + clauses.length +
", maxClauses=" + max;
if (bq.isCoordDisabled()) {
descr += ", coord=false";
}
if (bq.getMinimumNumberShouldMatch() > 0) {
descr += ", minShouldMatch=" + bq.getMinimumNumberShouldMatch();
}
setString(n1, "text", descr);
add(n, n1);
for (int i = 0; i < clauses.length; i++) {
n1 = create("node");
String occur;
Occur occ = clauses[i].getOccur();
if (occ.equals(Occur.MUST)) {
occur = "MUST";
} else if (occ.equals(Occur.MUST_NOT)) {
occur = "MUST_NOT";
} else if (occ.equals(Occur.SHOULD)) {
occur = "SHOULD";
} else {
occur = occ.toString();
}
setString(n1, "text", "Clause " + i + ": " + occur);
add(n, n1);
_explainStructure(n1, clauses[i].getQuery());
}
} else if (clazz.equals("lucene.PrefixQuery")) {
Object n1 = create("node");
PrefixQuery pq = (PrefixQuery)q;
Term t = pq.getPrefix();
setString(n1, "text", "Prefix: field='" + t.field() + "' text='" + t.text() + "'");
add(n, n1);
try {
addTermsEnum(n, PrefixQuery.class, pq.getField(), pq);
} catch (Exception e) {
e.printStackTrace();
n1 = create("node");
setString(n1, "text", "TermEnum: Exception " + e.getMessage());
add(n, n1);
}
} else if (clazz.equals("lucene.PhraseQuery")) {
PhraseQuery pq = (PhraseQuery)q;
setString(n, "text", getString(n, "text") + ", slop=" + pq.getSlop());
int[] pos = pq.getPositions();
Term[] terms = pq.getTerms();
Object n1 = create("node");
StringBuffer sb = new StringBuffer("pos: [");
for (int i = 0; i < pos.length; i++) {
if (i > 0) sb.append(',');
sb.append("" + pos[i]);
}
sb.append("]");
setString(n1, "text", sb.toString());
add(n, n1);
for (int i = 0; i < terms.length; i++) {
n1 = create("node");
setString(n1, "text", "Term " + i + ": field='" + terms[i].field() +
"' text='" + terms[i].text() + "'");
add(n, n1);
}
} else if (clazz.equals("lucene.MultiPhraseQuery")) {
MultiPhraseQuery pq = (MultiPhraseQuery)q;
setString(n, "text", getString(n, "text") + ", slop=" + pq.getSlop());
int[] pos = pq.getPositions();
Object n1 = create("node");
StringBuffer sb = new StringBuffer("pos: [");
for (int i = 0; i < pos.length; i++) {
if (i > 0) sb.append(',');
sb.append("" + pos[i]);
}
sb.append("]");
setString(n1, "text", sb.toString());
add(n, n1);
n1 = create("node");
System.err.println("MultiPhraseQuery is missing the public getTermArrays() :-(");
setString(n1, "text", "toString: " + pq.toString());
add(n, n1);
} else if (clazz.equals("lucene.FuzzyQuery")) {
FuzzyQuery fq = (FuzzyQuery)q;
Object n1 = create("node");
setString(n1, "text", "field=" + fq.getField() + ", prefixLen=" + fq.getPrefixLength() +
", maxEdits=" + df.format(fq.getMaxEdits()));
add(n, n1);
try {
addTermsEnum(n, FuzzyQuery.class, fq.getField(), fq);
} catch (Exception e) {
e.printStackTrace();
n1 = create("node");
setString(n1, "text", "TermEnum: Exception " + e.getMessage());
add(n, n1);
}
} else if (clazz.equals("lucene.WildcardQuery")) {
WildcardQuery wq = (WildcardQuery)q;
Term t = wq.getTerm();
setString(n, "text", getString(n, "text") + ", term=" + t);
Automaton a = WildcardQuery.toAutomaton(t);
addAutomaton(n, a);
} else if (clazz.equals("lucene.TermRangeQuery")) {
TermRangeQuery rq = (TermRangeQuery)q;
setString(n, "text", getString(n, "text") + ", inclLower=" + rq.includesLower() + ", inclUpper=" + rq.includesUpper());
Object n1 = create("node");
setString(n1, "text", "lowerTerm=" + rq.getField() + ":" + rq.getLowerTerm() + "'");
add(n, n1);
n1 = create("node");
setString(n1, "text", "upperTerm=" + rq.getField() + ":" + rq.getUpperTerm() + "'");
add(n, n1);
try {
addTermsEnum(n, TermRangeQuery.class, rq.getField(), rq);
} catch (Exception e) {
e.printStackTrace();
n1 = create("node");
setString(n1, "text", "TermEnum: Exception " + e.getMessage());
add(n, n1);
}
} else if (q instanceof AutomatonQuery) {
AutomatonQuery aq = (AutomatonQuery)q;
setString(n, "text", getString(n, "text") + ", " + aq.toString());
// get automaton
try {
java.lang.reflect.Field aField = AutomatonQuery.class.getDeclaredField("automaton");
aField.setAccessible(true);
Automaton a = (Automaton)aField.get(aq);
addAutomaton(n, a);
} catch (Exception e) {
e.printStackTrace();
Object n1 = create("node");
setString(n1, "text", "Automaton: Exception " + e.getMessage());
add(n, n1);
}
} else if (q instanceof MultiTermQuery) {
MultiTermQuery mq = (MultiTermQuery)q;
Set<Term> terms = new HashSet<Term>();
mq.extractTerms(terms);
setString(n, "text", getString(n, "text") + ", terms: " + terms);
try {
addTermsEnum(n, TermRangeQuery.class, mq.getField(), mq);
} catch (Exception e) {
e.printStackTrace();
Object n1 = create("node");
setString(n1, "text", "TermEnum: Exception " + e.getMessage());
add(n, n1);
}
} else if (q instanceof ConstantScoreQuery) {
ConstantScoreQuery cq = (ConstantScoreQuery)q;
setString(n, "text", getString(n, "text") + ", " + cq.toString());
Object n1 = create("node");
add(n, n1);
if (cq.getFilter() != null) {
setString(n1, "text", "Filter: " + cq.getFilter().toString());
} else if (cq.getQuery() != null) {
_explainStructure(n, cq.getQuery());
}
} else if (q instanceof FilteredQuery) {
FilteredQuery fq = (FilteredQuery)q;
Object n1 = create("node");
setString(n1, "text", "Filter: " + fq.getFilter().toString());
add(n, n1);
_explainStructure(n, fq.getQuery());
} else if (q instanceof SpanQuery) {
SpanQuery sq = (SpanQuery)q;
Class sqlass = sq.getClass();
setString(n, "text", getString(n, "text") + ", field=" + sq.getField());
if (sqlass == SpanOrQuery.class) {
SpanOrQuery soq = (SpanOrQuery)sq;
setString(n, "text", getString(n, "text") + ", " + soq.getClauses().length + " clauses");
for (SpanQuery sq1 : soq.getClauses()) {
_explainStructure(n, sq1);
}
} else if (sqlass == SpanFirstQuery.class) {
SpanFirstQuery sfq = (SpanFirstQuery)sq;
setString(n, "text", getString(n, "text") + ", end=" + sfq.getEnd() + ", match:");
_explainStructure(n, sfq.getMatch());
} else if (q instanceof SpanNearQuery) { // catch also known subclasses
SpanNearQuery snq = (SpanNearQuery)sq;
setString(n, "text", getString(n, "text") + ", slop=" + snq.getSlop());
if (snq instanceof PayloadNearQuery) {
try {
java.lang.reflect.Field function = PayloadNearQuery.class.getDeclaredField("function");
function.setAccessible(true);
Object func = function.get(snq);
setString(n, "text", getString(n, "text") + ", func=" + func.getClass().getSimpleName());
} catch (Exception e) {
e.printStackTrace();
}
}
for (SpanQuery sq1 : snq.getClauses()) {
_explainStructure(n, sq1);
}
} else if (sqlass == SpanNotQuery.class) {
SpanNotQuery snq = (SpanNotQuery)sq;
Object n1 = create("node");
add(n, n1);
setString(n1, "text", "Include:");
_explainStructure(n1, snq.getInclude());
n1 = create("node");
add(n, n1);
setString(n1, "text", "Exclude:");
_explainStructure(n1, snq.getExclude());
} else if (q instanceof SpanTermQuery) {
SpanTermQuery stq = (SpanTermQuery)sq;
setString(n, "text", getString(n, "text") + ", term=" + stq.getTerm());
if (stq instanceof PayloadTermQuery) {
try {
java.lang.reflect.Field function = PayloadTermQuery.class.getDeclaredField("function");
function.setAccessible(true);
Object func = function.get(stq);
setString(n, "text", getString(n, "text") + ", func=" + func.getClass().getSimpleName());
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
String defField = getDefaultField(find("srchOptTabs"));
setString(n, "text", "class=" + q.getClass().getName() + ", " + getString(n, "text") + ", toString=" + q.toString(defField));
HashSet<Term> terms = new HashSet<Term>();
sq.extractTerms(terms);
Object n1 = null;
if (terms != null) {
n1 = create("node");
setString(n1, "text", "Matched terms (" + terms.size() + "):");
add(n, n1);
Iterator<Term> it = terms.iterator();
while(it.hasNext()) {
Object n2 = create("node");
Term t = it.next();
setString(n2, "text", "field='" + t.field() + "' text='" + t.text() + "'");
add(n1, n2);
}
} else {
n1 = create("node");
setString(n1, "text", "<no terms matched>");
add(n, n1);
}
}
if (ir != null) {
Object n1 = null;
/* in Lucene 4.0 this requires traversal of sub- and leaf readers,
* which is cumbersome to do here.
try {
Spans spans = sq.getSpans(ir);
if (spans != null) {
n1 = create("node");
int cnt = 0;
while (spans.next()) {
Object n2 = create("node");
setString(n2, "text", "doc=" + spans.doc() +
", start=" + spans.start() + ", end=" + spans.end());
add(n1, n2);
cnt++;
}
if (cnt > 0) {
add(n, n1);
setString(n1, "text", "Spans (" + cnt + "):");
setBoolean(n1, "expanded", false);
}
}
} catch (Exception e) {
e.printStackTrace();
n1 = create("node");
setString(n1, "text", "Spans Exception: " + e.getMessage());
add(n, n1);
}
*/
}
} else {
Object n1 = create("node");
String defField = getDefaultField(find("srchOptTabs"));
Set<Term> terms = new HashSet<Term>();
q.extractTerms(terms);
setString(n1, "text", q.getClass().getName() + ": " + q.toString(defField));
add(n, n1);
if (!terms.isEmpty()) {
n1 = create("node");
setString(n1, "text", "terms: " + terms);
add(n, n1);
}
}
}
private void addAutomaton(Object parent, Automaton a) {
Object n = create("node");
setString(n, "text", "Automaton: " + a != null ? a.toDot() : "null");
add(parent, n);
int numStates = a.getNumStates();
for(int s=0;s<numStates;s++) {
Object n1 = create("node");
add(n, n1);
StringBuilder msg = new StringBuilder();
msg.append(String.valueOf(s));
if (0 == s) {
msg.append(" INITIAL");
}
msg.append(a.isAccept(s) ? " [accept]" : " [reject]");
msg.append(", "); msg.append(a.getNumTransitions(s));msg.append(" transitions");
setString(n1, "text", msg.toString());
Transition t = new Transition();
int count = a.initTransition(s, t);
for (int i=0;i<count;i++) {
a.getNextTransition(t);
Object n2 = create("node");
add(n1, n2);
setString(n2, "text", t.toString());
}
}
}
private void addTermsEnum(Object parent, Class<? extends Query> clz, String field, Query instance) throws Exception {
Method m = clz.getDeclaredMethod("getTermsEnum", Terms.class, AttributeSource.class);
m.setAccessible(true);
Terms terms = ar.terms(field);
TermsEnum fte = (TermsEnum)m.invoke(instance, terms, new AttributeSource());
Object n1 = create("node");
String clazz = fte.getClass().getName();
setString(n1, "text", clazz);
add(parent, n1);
while (fte.next() != null) {
Object n2 = create("node");
setString(n2, "text", "'" + fte.term().utf8ToString() + "', docFreq=" + fte.docFreq() + ", totalTermFreq=" + fte.totalTermFreq());
add(n1, n2);
}
}
public void clipQExplain(Object qExplain) {
Object tree = find(qExplain, "qTree");
StringBuilder sb = new StringBuilder();
treeToString(tree, sb);
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
private void treeToString(Object tree, StringBuilder sb) {
if (tree == null) {
return;
}
Object[] items = getItems(tree);
if (items == null || items.length == 0) {
return;
}
for (int i = 0; i < items.length; i++) {
if (i > 0) {
sb.append('\n');
}
treeNodeToString(items[i], sb, 0);
}
}
private void treeNodeToString(Object node, StringBuilder sb, int level) {
for (int i = 0; i < level; i++) {
sb.append(' ');
}
sb.append(getString(node, "text"));
Object[] items = getItems(node);
if (items != null && items.length > 0) {
sb.append('\n');
for (int i = 0; i < items.length; i++) {
if (i > 0) {
sb.append('\n');
}
treeNodeToString(items[i], sb, level + 2);
}
}
}
/**
* Update the parsed and rewritten query views.
*
*/
public void showParsed() {
Object qField = find("qField");
Object qFieldParsed = find("qFieldParsed");
Object qFieldRewritten = find("qFieldRewritten");
String queryS = getString(qField, "text");
if (queryS.trim().equals("")) {
setString(qFieldParsed, "text", "<empty query>");
setBoolean(qFieldParsed, "enabled", false);
return;
} else {
setBoolean(qFieldParsed, "enabled", true);
}
try {
Query q = createQuery(queryS);
if (q == null) {
return;
}
setString(qFieldParsed, "text", q.toString());
putProperty(qField, "qParsed", q);
q = q.rewrite(ir);
setString(qFieldRewritten, "text", q.toString());
putProperty(qField, "qRewritten", q);
} catch (Throwable t) {
t.printStackTrace();
setString(qFieldParsed, "text", t.getMessage());
setString(qFieldRewritten, "text", t.getMessage());
}
}
/**
* Perform a search. NOTE: this method is usually invoked from the GUI.
* @param qField Thinlet widget containing the query
*/
public void search(Object qField) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (ir.numDocs() == 0) {
showStatus(MSG_EMPTY_INDEX);
return;
}
String queryS = getString(qField, "text");
if (queryS.trim().equals("")) {
showStatus("FAILED: Empty query.");
return;
}
Object srchOpts = find("srchOptTabs");
// query parser opts
Similarity sim = createSimilarity(srchOpts);
AccessibleHitCollector col;
try {
col = createCollector(srchOpts);
} catch (Throwable t) {
errorMsg("ERROR creating Collector: " + t.getMessage());
return;
}
Object sTable = find("sTable");
Object cntRepeat = find("cntRepeat");
int repeat = Integer.parseInt(getString(cntRepeat, "text"));
removeAll(sTable);
Query q = null;
try {
q = createQuery(queryS);
if (q == null) {
return;
}
is.setSimilarity(sim);
showParsed();
_search(q, is, col, sTable, repeat);
} catch (Throwable e) {
e.printStackTrace();
errorMsg(e.getMessage());
}
}
int resStart = 0;
int resCount = 20;
LimitedException le = null;
private void _search(final Query q, final IndexSearcher is,
AccessibleHitCollector hc, final Object sTable, final int repeat) throws Exception {
if (hc == null) {
hc = new AccessibleTopHitCollector(1000, true, true);
}
final AccessibleHitCollector collector = hc;
le = null;
SlowThread t = new SlowThread(this) {
public void execute() {
long startTime = System.nanoTime();
for (int i = 0; i < repeat; i++) {
if (i > 0) {
collector.reset();
}
try {
is.search(q, collector);
} catch (LimitedException e) {
le = e;
} catch (Throwable th) {
th.printStackTrace();
errorMsg("ERROR searching: " + th.toString());
return;
}
}
long endTime = System.nanoTime();
long delta = (endTime - startTime) / 1000 / repeat;
String msg;
if (delta > 100000) {
msg = delta / 1000 + " ms";
} else {
msg = delta + " us";
}
if (repeat > 1) {
msg += " (avg of " + repeat + " runs)";
}
showSearchStatus(msg);
Object bsPrev = find("bsPrev");
Object bsNext = find("bsNext");
setBoolean(bsNext, "enabled", false);
setBoolean(bsPrev, "enabled", false);
int resNum = collector.getTotalHits();
if (resNum == 0) {
Object row = create("row");
Object cell = create("cell");
add(sTable, row);
add(row, cell);
cell = create("cell");
add(row, cell);
cell = create("cell");
setString(cell, "text", "No Results");
setBoolean(cell, "enabled", false);
add(row, cell);
setString(find("resNum"), "text", "0");
return;
}
if (resNum > resCount) {
setBoolean(bsNext, "enabled", true);
}
setString(find("resNum"), "text", String.valueOf(resNum));
putProperty(sTable, "resNum", new Integer(resNum));
putProperty(sTable, "query", q);
putProperty(sTable, "hc", collector);
if (le != null) {
putProperty(sTable, "le", le);
}
resStart = 0;
_showSearchPage(sTable);
}
};
if (slowAccess) {
t.start();
} else {
t.execute();
}
}
public void prevPage(Object sTable) {
int resNum = ((Integer)getProperty(sTable, "resNum")).intValue();
if (resStart == 0) {
setBoolean(find("bsPrev"), "enabled", false);
return;
}
resStart -= resCount;
if (resStart < 0) resStart = 0;
if (resStart - resCount < 0)
setBoolean(find("bsPrev"), "enabled", false);
if (resStart + resCount < resNum)
setBoolean(find("bsNext"), "enabled", true);
_showSearchPage(sTable);
}
public void nextPage(Object sTable) {
int resNum = ((Integer)getProperty(sTable, "resNum")).intValue();
resStart += resCount;
if (resStart >= resNum) {
resStart -= resCount;
setBoolean(find("bsNext"), "enabled", false);
return;
}
setBoolean(find("bsPrev"), "enabled", true);
if (resStart + resCount >= resNum) {
setBoolean(find("bsNext"), "enabled", false);
}
_showSearchPage(sTable);
}
private void _showSearchPage(final Object sTable) {
SlowThread t = new SlowThread(this) {
public void execute() {
try {
removeAll(sTable);
AccessibleHitCollector hc = (AccessibleHitCollector)getProperty(sTable, "hc");
int resNum = hc.getTotalHits();
int max = Math.min(resNum, resStart + resCount);
Object posLabel = find("resPos");
setString(posLabel, "text", resStart + "-" + (max - 1));
for (int i = resStart; i < max; i++) {
int docid = hc.getDocId(i);
float score = hc.getScore(i);
_createResultRow(i, docid, score, sTable);
}
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
t.start();
} else {
t.execute();
}
}
private void _createResultRow(int pos, int docId, float score, Object sTable) throws IOException {
Object row = create("row");
Object cell = create("cell");
add(sTable, row);
setString(cell, "text", String.valueOf(pos));
setChoice(cell, "alignment", "right");
add(row, cell);
cell = create("cell");
setString(cell, "text", String.valueOf(df.format(score)));
setChoice(cell, "alignment", "right");
add(row, cell);
cell = create("cell");
setString(cell, "text", String.valueOf(docId));
setChoice(cell, "alignment", "right");
add(row, cell);
Document doc = ir.document(docId);
putProperty(row, "docid", new Integer(docId));
StringBuffer vals = new StringBuffer();
for (int j = 0; j < idxFields.length; j++) {
cell = create("cell");
Decoder dec = decoders.get(idxFields[j]);
if (dec == null) dec = defDecoder;
IndexableField[] values = doc.getFields(idxFields[j]);
vals.setLength(0);
boolean decodeErr = false;
if (values != null) for (int k = 0; k < values.length; k++) {
if (k > 0) vals.append(' ');
String v;
try {
v = dec.decodeStored(idxFields[j], (Field)values[k]);
} catch (Throwable e) {
e.printStackTrace();
v = values[k].stringValue();
decodeErr = true;
}
vals.append(Util.escape(v));
}
setString(cell, "text", vals.toString());
if (decodeErr) {
setColor(cell, "foreground", Color.RED);
}
add(row, cell);
}
}
/**
* Pop up a modal dialog explaining the selected result.
* @param sTable Thinlet table widget containing selected search result.
*/
public void explainResult(Object sTable) {
Object row = getSelectedItem(sTable);
if (row == null) return;
final Integer docid = (Integer) getProperty(row, "docid");
if (docid == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
final Query q = (Query) getProperty(sTable, "query");
if (q == null) return;
Thread t = new Thread() {
public void run() {
try {
IndexSearcher is = new IndexSearcher(ir);
Similarity sim = createSimilarity(find("srchOptTabs"));
is.setSimilarity(sim);
Explanation expl = is.explain(q, docid.intValue());
Object dialog = addComponent(null, "/xml/explain.xml", null, null);
Object eTree = find(dialog, "eTree");
addNode(eTree, expl);
//setBoolean(eTree, "expand", true);
add(dialog);
} catch (Exception e) {
e.printStackTrace();
errorMsg(e.getMessage());
}
}
};
if (slowAccess) {
t.start();
} else {
t.run();
}
}
public void clipExplain(Object explain) {
Object eTree = find(explain, "eTree");
StringBuilder sb = new StringBuilder();
treeToString(eTree, sb);
StringSelection sel = new StringSelection(sb.toString());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, this);
}
private DecimalFormat df = new DecimalFormat("0.0000");
private String xmlQueryParserFactoryClassName=CorePlusExtensionsParserFactory.class.getName();
private void addNode(Object tree, Explanation expl) {
Object node = create("node");
setString(node, "text", df.format((double) expl.getValue()) + " " + expl.getDescription());
add(tree, node);
if (getClass(tree) == "tree") {
setFont(node, getFont().deriveFont(Font.BOLD));
}
Explanation[] kids = expl.getDetails();
if (kids != null && kids.length > 0) {
for (int i = 0; i < kids.length; i++) {
addNode(node, kids[i]);
}
}
}
public void gotoDoc(Object sTable) {
Object row = getSelectedItem(sTable);
if (row == null) return;
final Integer docid = (Integer) getProperty(row, "docid");
if (docid == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
Document doc = null;
try {
doc = ir.document(docid.intValue());
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
return;
}
_showDocFields(docid.intValue(), doc);
Object tabpane = find("maintpane");
setInteger(tabpane, "selected", 1);
repaint();
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
private void _showTermDoc(Object fText, final DocsEnum td) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
SlowThread st = new SlowThread(this) {
public void execute() {
try {
Document doc = ir.document(td.docID());
setString(find("docNum"), "text", String.valueOf(td.docID()));
setString(find("tFreq"), "text", String.valueOf(td.freq()));
_showDocFields(td.docID(), doc);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
};
if (slowAccess) {
st.start();
} else {
st.execute();
}
}
public void deleteTermDoc(Object fText) {
Term t = (Term) getProperty(fText, "term");
if (t == null) return;
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (readOnly) {
showStatus(MSG_READONLY);
return;
}
try {
IndexWriter iw = createIndexWriter();
iw.deleteDocuments(t);
iw.close();
refreshAfterWrite();
infoMsg("Deleted docs for query '" + t + "'. Term dictionary and statistics will be incorrect until next merge or expunge deletes.");
} catch (Exception e) {
e.printStackTrace();
errorMsg("Error deleting doc: " + e.toString());
}
}
public void deleteDocs(Object sTable) {
if (ir == null) {
showStatus(MSG_NOINDEX);
return;
}
if (readOnly) {
showStatus(MSG_READONLY);
return;
}
Query q = (Query)getProperty(sTable, "query");
if (q == null) {
errorMsg("Empty query.");
return;
}
removeAll(sTable);
try {
IndexWriter iw = createIndexWriter();
iw.deleteDocuments(q);
iw.close();
refreshAfterWrite();
infoMsg("Deleted docs for query '" + q + "'. Term dictionary and statistics will be incorrect until next merge or expunge deletes.");
} catch (Throwable e) {
e.printStackTrace();
errorMsg("Error deleting documents: " + e.toString());
}
}
public void actionAbout() {
Object about = addComponent(this, "/xml/about.xml", null, null);
Object lver = find(about, "lver");
setString(lver, "text", "Lucene version: " + LucenePackage.get().getImplementationVersion());
}
/**
* Pop up a modal font selection dialog.
*
*/
public void actionShowFonts() {
addComponent(this, "/xml/selfont.xml", null, null);
}
/**
* Initialize the font selection dialog.
* @param selfont font selection dialog
*/
public void setupSelFont(Object selfont) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
Font[] fonts = ge.getAllFonts();
Object cbFonts = find(selfont, "fonts");
String curfont = getFont().getFontName();
float cursize = getFont().getSize2D();
Object fsize = find(selfont, "fsize");
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(1);
setString(fsize, "text", nf.format(cursize));
removeAll(cbFonts);
Object def = create("choice");
setFont(def, "font", getFont().deriveFont(15.0f));
setString(def, "text", curfont + " (default)");
putProperty(def, "fnt", getFont());
add(cbFonts, def);
setInteger(cbFonts, "selected", 0);
for (int i = 0; i < fonts.length; i++) {
Object choice = create("choice");
setFont(choice, "font", fonts[i].deriveFont(15.0f));
setString(choice, "text", fonts[i].getFontName());
putProperty(choice, "fnt", fonts[i]);
add(cbFonts, choice);
if (curfont.equalsIgnoreCase(fonts[i].getFontName()))
setInteger(cbFonts, "selected", i + 1);
}
}
/**
* Show preview of the selected font.
* @param selfont font selection dialog
*/
public void selectFont(Object selfont) {
Object preview = find(selfont, "fpreview");
Object cbFonts = find(selfont, "fonts");
Object fsize = find(selfont, "fsize");
Font f = (Font)getProperty(getSelectedItem(cbFonts), "fnt");
float size = getFont().getSize2D();
try {
size = Float.parseFloat(getString(fsize, "text"));
} catch (Exception e) {
e.printStackTrace();
}
f = f.deriveFont(size);
Object[] items = getItems(preview);
for (int i = 0; i < items.length; i++) {
setPreviewFont(f, items[i]);
}
}
private void setPreviewFont(Font f, Object item) {
try {
setFont(item, "font", f);
} catch (IllegalArgumentException iae) {
// shrug...
}
Object[] items = getItems(item);
for (int i = 0; i < items.length; i++) {
setPreviewFont(f, items[i]);
}
}
/**
* Set the default font in the UI.
* @param selfont font selection dialog
*/
public void actionSetFont(Object selfont) {
Object cbFonts = find(selfont, "fonts");
Object fsize = find(selfont, "fsize");
Font f = (Font)getProperty(getSelectedItem(cbFonts), "fnt");
float size = getFont().getSize2D();
try {
size = Float.parseFloat(getString(fsize, "text"));
} catch (Exception e) {
e.printStackTrace();
}
f = f.deriveFont(size);
remove(selfont);
setFont(f);
courier = new Font("Courier", getFont().getStyle(), getFont().getSize());
repaint();
}
public void actionSetDecoder(Object fList, Object combo) {
Object row = getSelectedItem(fList);
if (row == null) {
return;
}
String fName = (String)getProperty(row, "fName");
Object choice = getSelectedItem(combo);
String decName = getString(choice, "name");
Decoder dec = null;
if (decName.equals("s")) {
dec = new StringDecoder();
} else if (decName.equals("b")) {
dec = new BinaryDecoder();
} else if (decName.equals("d")) {
dec = new DateDecoder();
} else if (decName.equals("nl")) {
dec = new NumLongDecoder();
} else if (decName.equals("ni")) {
dec = new NumIntDecoder();
} else if (decName.startsWith("solr.")) {
try {
dec = new SolrDecoder(decName);
} catch (Exception e) {
e.printStackTrace();
errorMsg("Error setting decoder: " + e.toString());
}
} else {
dec = defDecoder;
}
decoders.put(fName, dec);
Object cell = getItem(row, 3);
setString(cell, "text", dec.toString());
repaint(fList);
actionTopTerms(find("nTerms"));
}
/**
* Returns current custom similarity implementation.
* @return
*/
public Similarity getCustomSimilarity() {
return similarity;
}
private static TFIDFSimilarity defaultSimilarity = new DefaultSimilarity();
/**
* Set the current custom similarity implementation.
* @param s
*/
public void setCustomSimilarity(Similarity s) {
similarity = s;
Object cbSimCust = find("ckSimCust");
Object cbSimDef = find("ckSimDef");
Object simName = find("simName");
if (similarity != null) {
setString(simName, "text", similarity.getClass().getName());
setBoolean(cbSimCust, "enabled", true);
} else {
setString(simName, "text", "");
setBoolean(cbSimCust, "enabled", false);
setBoolean(cbSimDef, "selected", true);
setBoolean(cbSimCust, "selected", false);
}
}
/**
* Switch the view to display the SimilarityDesigner plugin, if present.
*
*/
public void actionDesignSimilarity() {
LukePlugin designer = null;
for (int i = 0; i < plugins.size(); i++) {
if (plugins.get(i).getClass().getName().equals("org.getopt.luke.plugins.SimilarityDesignerPlugin")) {
designer = (LukePlugin)plugins.get(i);
break;
}
}
if (designer == null) {
showStatus("Designer Plugin not available");
return;
}
// a bit tricky: plugins are put within panels, and these in tabs
Object pluginsTab = find("pluginsTab");
Object maintab = getParent(pluginsTab);
int index = getIndex(maintab, pluginsTab);
setInteger(maintab, "selected", index);
Object pluginsTabs = find("pluginsTabs");
Object tab = getParent(getParent(designer.getMyUi()));
index = getIndex(pluginsTabs, tab);
setInteger(pluginsTabs, "selected", index);
repaint();
}
/**
* Shut down Luke. If {@link #exitOnDestroy} is true (such as when Luke was
* started from the main method), invoke also System.exit().
*/
public boolean destroy() {
if (ir != null) try {
ir.close();
} catch (Exception e) {}
;
if (ar != null) try {
ar.close();
} catch (Exception e) {}
;
if (dir != null) try {
dir.close();
} catch (Exception e) {}
;
try {
Prefs.save();
} catch (Exception e) {}
;
if (exitOnDestroy) System.exit(0);
return super.destroy();
}
public void actionExit() {
destroy();
}
/**
* Open URL in the system default browser.
* @param url
*/
public void goUrl(Object url) {
String u = (String) getProperty(url, "url");
if (u == null) return;
try {
BrowserLauncher.openURL(u);
} catch (Exception e) {
e.printStackTrace();
showStatus(e.getMessage());
}
}
/**
* Start the GUI, and optionally open an index.
* @param args index parameters
* @return fully initialized Luke instance
*/
public static Luke startLuke(String[] args) {
Luke luke = new Luke();
FrameLauncher f = new FrameLauncher("Luke - Lucene Index Toolbox, v "+LucenePackage.get().getImplementationVersion(), luke, 850, 650);
f.setIconImage(Toolkit.getDefaultToolkit().createImage(Luke.class.getResource("/img/luke.gif")));
if (args.length > 0) {
boolean force = false, ro = false, ramdir = false;
String pName = null;
String script = null;
String xmlQueryParserFactoryClassName = null;
for (int i = 0; i < args.length; i++) {
if (args[i].equalsIgnoreCase("-ro")) ro = true;
else if (args[i].equalsIgnoreCase("-force")) force = true;
else if (args[i].equalsIgnoreCase("-ramdir")) ramdir = true;
else if (args[i].equalsIgnoreCase("-index")) pName = args[++i];
else if (args[i].equalsIgnoreCase("-script")) script = args[++i];
else if (args[i].equalsIgnoreCase("-xmlQueryParserFactory")) xmlQueryParserFactoryClassName = args[++i];
else {
System.err.println("Unknown argument: " + args[i]);
usage();
luke.actionExit();
return null;
}
}
if (pName != null) luke.openIndex(pName, force, null, ro, ramdir, false, null, 1);
if(xmlQueryParserFactoryClassName != null) luke.setParserFactoryClassName(xmlQueryParserFactoryClassName);
if (script != null) {
LukePlugin plugin = luke.getPlugin("org.getopt.luke.plugins.ScriptingPlugin");
if (plugin == null) {
String msg = "ScriptingPlugin not present - cannot execute scripts.";
System.err.println(msg);
luke.actionExit();
} else {
((ScriptingPlugin)plugin).execute("load('" + script + "');");
}
}
} else luke.actionOpen();
return luke;
}
private void setParserFactoryClassName(String xmlQueryParserFactoryClassName) {
this.xmlQueryParserFactoryClassName = xmlQueryParserFactoryClassName;
}
/**
* Main method. If you just want to instantiate Luke from other classes or scripts,
* use {@link #startLuke(String[])} instead.
* @param args
*/
public static void main(String[] args) {
exitOnDestroy = true;
startLuke(args);
}
public static void usage() {
System.err.println("Command-line usage:\n");
System.err.println("Luke [-index path_to_index] [-ro] [-force] [-mmap] [-script filename]\n");
System.err.println("\t-index path_to_index\topen this index");
System.err.println("\t-ro\topen index read-only");
System.err.println("\t-force\tforce unlock if the index is locked (use with caution)");
System.err.println("\t-xmlQueryParserFactory\tFactory for loading custom XMLQueryParsers. E.g.:");
System.err.println("\t\t\torg.getopt.luke.xmlQuery.CoreParserFactory (default)");
System.err.println("\t\t\torg.getopt.luke.xmlQuery.CorePlusExtensionsParserFactory");
System.err.println("\t-mmap\tuse MMapDirectory");
System.err.println("\t-script filename\trun this script using the ScriptingPlugin.");
System.err.println("\t\tIf an index name is specified, the index is open prior to");
System.err.println("\t\tstarting the script. Note that you need to escape special");
System.err.println("\t\tcharacters twice - first for shell and then for JavaScript.");
}
/*
* (non-Javadoc)
*
* @see java.awt.datatransfer.ClipboardOwner#lostOwnership(java.awt.datatransfer.Clipboard,
* java.awt.datatransfer.Transferable)
*/
public void lostOwnership(Clipboard arg0, Transferable arg1) {
}
/**
* @return the numTerms
*/
public int getNumTerms() {
return numTerms;
}
}