SOLR-3121: (admin UI) load term info dynamically for each field

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1242998 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Ryan McKinley 2012-02-11 02:55:45 +00:00
parent bea8fd0fb6
commit 7e3a10e107
4 changed files with 303 additions and 237 deletions

View File

@ -31,13 +31,13 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRef;
import org.apache.lucene.util.PriorityQueue;
import org.apache.lucene.util.ReaderUtil;
import org.apache.lucene.util.UnicodeUtil;
import org.apache.solr.analysis.CharFilterFactory;
import org.apache.solr.analysis.TokenFilterFactory;
import org.apache.solr.analysis.TokenizerChain;
import org.apache.solr.analysis.TokenizerFactory;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.luke.FieldFlag;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
@ -84,6 +84,23 @@ public class LukeRequestHandler extends RequestHandlerBase
public static final int DEFAULT_COUNT = 10;
static final int HIST_ARRAY_SIZE = 33;
private static enum ShowStyle {
ALL,
DOC,
SCHEMA,
INDEX;
public static ShowStyle get(String v) {
if(v==null) return null;
if("schema".equals(v)) return SCHEMA;
if("index".equals(v)) return INDEX;
if("doc".equals(v)) return DOC;
if("all".equals(v)) return ALL;
throw new SolrException(ErrorCode.BAD_REQUEST, "Unknown Show Style: "+v);
}
};
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception
@ -93,6 +110,7 @@ public class LukeRequestHandler extends RequestHandlerBase
DirectoryReader reader = searcher.getIndexReader();
SolrParams params = req.getParams();
int numTerms = params.getInt( NUMTERMS, DEFAULT_COUNT );
ShowStyle style = ShowStyle.get(params.get("show"));
// Always show the core lucene info
Map<String, TopTermQueue> topTerms = new TreeMap<String, TopTermQueue>();
@ -103,12 +121,17 @@ public class LukeRequestHandler extends RequestHandlerBase
if (fl != null) {
fields = new TreeSet<String>(Arrays.asList(fl.split( "[,\\s]+" )));
}
if ( "schema".equals( params.get( "show" ))) {
if( ShowStyle.SCHEMA == style ) {
numTerms = 0; // Abort any statistics gathering.
}
rsp.add("index", getIndexInfo(reader, numTerms, topTerms, fields ));
rsp.add("index", getIndexInfo(reader, numTerms, topTerms, fields ));
if(ShowStyle.INDEX==style) {
return; // thats all we need
}
Integer docId = params.getInt( DOC_ID );
if( docId == null && params.get( ID ) != null ) {
// Look for something with a given solr ID
@ -123,6 +146,9 @@ public class LukeRequestHandler extends RequestHandlerBase
// Read the document from the index
if( docId != null ) {
if( style != null && style != ShowStyle.DOC ) {
throw new SolrException(ErrorCode.BAD_REQUEST, "missing doc param for doc style");
}
Document doc = null;
try {
doc = reader.document( docId );
@ -140,7 +166,7 @@ public class LukeRequestHandler extends RequestHandlerBase
docinfo.add( "solr", doc );
rsp.add( "doc", docinfo );
}
else if ( "schema".equals( params.get( "show" ) ) ) {
else if ( ShowStyle.SCHEMA == style ) {
rsp.add( "schema", getSchemaInfo( req.getSchema() ) );
}
else {
@ -559,11 +585,13 @@ public class LukeRequestHandler extends RequestHandlerBase
indexInfo.add("numTerms", (new Long(totalTerms)).intValue());
}
indexInfo.add("version", reader.getVersion()); // TODO? Is this different then: IndexReader.getCurrentVersion( dir )?
indexInfo.add("segmentCount", reader.getSequentialSubReaders().length);
indexInfo.add("current", reader.isCurrent() );
indexInfo.add("hasDeletions", reader.hasDeletions() );
indexInfo.add("directory", dir );
indexInfo.add("userData", reader.getIndexCommit().getUserData());
String s = reader.getIndexCommit().getUserData().get(SolrIndexWriter.COMMIT_TIME_MSEC_KEY);
if (s != null) {
indexInfo.add("lastModified", new Date(Long.parseLong(s)));

View File

@ -1766,7 +1766,7 @@ var sammy = $.sammy
$.ajax
(
{
url : core_basepath + '/admin/luke?numTerms=50&wt=json',
url : core_basepath + '/admin/luke?numTerms=0&wt=json',
dataType : 'json',
beforeSend : function( xhr, settings )
{
@ -1860,28 +1860,6 @@ var sammy = $.sammy
for( var field in app.schema_browser_data.fields )
{
if( app.schema_browser_data.fields[field].histogram )
{
var histogram = app.schema_browser_data.fields[field].histogram;
app.schema_browser_data.fields[field].histogram =
luke_array_to_struct( histogram );
app.schema_browser_data.fields[field].histogram_hash =
luke_array_to_hash( histogram );
}
if( app.schema_browser_data.fields[field].topTerms )
{
var top_terms = app.schema_browser_data.fields[field].topTerms;
app.schema_browser_data.fields[field].topTerms =
luke_array_to_struct( top_terms );
app.schema_browser_data.fields[field].topTerms_hash =
luke_array_to_hash( top_terms );
}
if( app.schema_browser_data.fields[field].copySourcesRaw )
{
var copy_sources = app.schema_browser_data.fields[field].copySourcesRaw;
@ -2375,154 +2353,221 @@ var sammy = $.sammy
}
}
}
var terminfo_element = $( '.terminfo-holder', data_element );
if( is_f ) {
// ideally we would have a checkbox to enable loading topterms
// stored as a cookie? so it stays the same
// TopTerms on a big index is really a DOS attack!
core_basepath = "/solr"; // TODO?????
var status_holder_element = $( '.status-holder', terminfo_element );
var topterms_holder_element = $( '.topterms-holder', terminfo_element );
var histogram_holder_element = $( '.histogram-holder', terminfo_element );
topterms_holder_element.hide();
histogram_holder_element.hide();
$.ajax
(
{
url : core_basepath + '/admin/luke?numTerms=50&wt=json&fl=' + field,
dataType : 'json',
context : status_holder_element,
beforeSend : function( xhr, settings )
{
this.show();
this
.html( '<div value="">Loading Term Info... </div>' )
.addClass( 'loader' );
},
success : function( response, text_status, xhr )
{
var finfo = response['fields'][field];
if( finfo ) {
this
.html( '<div value=""><b>'+field+'</b> in '+finfo['docs']+' docs. '+finfo['distinct']+' distinct terms.</div><br/>' )
.removeClass( 'loader' );
console.log(finfo);
// TODO!!! this is duplicate code!!!!
var luke_array_to_struct = function( array )
{
var struct = {
keys : [],
values : []
};
for( var i = 0; i < array.length; i += 2 )
{
struct.keys.push( array[i] );
struct.values.push( array[i+1] );
}
return struct;
}
var topterms_holder_element = $( '.topterms-holder', data_element );
if( is_f && schema_browser_data.fields[field] && schema_browser_data.fields[field].topTerms_hash )
{
topterms_holder_element
.show();
var luke_array_to_hash = function( array )
{
var hash = {};
for( var i = 0; i < array.length; i += 2 )
{
hash[ array[i] ] = array[i+1];
}
return hash;
}
if( finfo.histogram )
{
var histogram = luke_array_to_struct( finfo.histogram );
var histogram_values = luke_array_to_hash ( finfo.histogram );
histogram_holder_element.show();
var histogram_element = $( '.histogram', histogram_holder_element );
var histogram_legend = '';
for( var key in histogram_values )
{
histogram_legend += '<dt><span>' + key + '</span></dt>' + "\n" +
'<dd title="' + key + '">' +
'<span>' + histogram_values[key] + '</span>' +
'</dd>' + "\n";
}
$( 'dl', histogram_holder_element )
.html( histogram_legend );
histogram_element.sparkline
(
histogram.values,
{
type : 'bar',
barColor : '#c0c0c0',
zeroColor : '#ffffff',
height : histogram_element.height(),
barWidth : 46,
barSpacing : 3
}
);
}
var topterms_table_element = $( 'table', topterms_holder_element );
var topterms_navi_less = $( 'p.navi .less', topterms_holder_element );
var topterms_navi_more = $( 'p.navi .more', topterms_holder_element );
var topterms_count = schema_browser_data.fields[field].topTerms.keys.length;
var topterms_hash = schema_browser_data.fields[field].topTerms_hash;
var topterms_content = '<tbody>';
var i = 1;
for( var term in topterms_hash )
{
topterms_content += '<tr>' + "\n" +
'<td class="position">' + i + '</td>' + "\n" +
'<td class="term">' + term + '</td>' + "\n" +
'<td class="frequency">' + topterms_hash[term] + '</td>' + "\n" +
'</tr>' + "\n";
if( i !== topterms_count && 0 === i % 10 )
{
topterms_content += '</tbody><tbody>';
}
i++;
}
topterms_content += '</tbody>';
topterms_table_element
.empty()
.append( topterms_content );
$( 'tbody', topterms_table_element )
.die( 'change' )
.live
(
'change',
function()
{
var blocks = $( 'tbody', topterms_table_element );
var visible_blocks = blocks.filter( ':visible' );
var hidden_blocks = blocks.filter( ':hidden' );
$( 'p.head .shown', topterms_holder_element )
.html( $( 'tr', visible_blocks ).size() );
0 < hidden_blocks.size()
? topterms_navi_more.show()
: topterms_navi_more.hide();
1 < visible_blocks.size()
? topterms_navi_less.show()
: topterms_navi_less.hide();
}
);
$( 'tbody tr:odd', topterms_table_element )
.addClass( 'odd' );
$( 'tbody:first', topterms_table_element )
.show()
.trigger( 'change' );
$( 'p.head .max', topterms_holder_element )
.html( schema_browser_data.fields[field].distinct );
topterms_navi_less
.die( 'click' )
.live
(
'click',
function( event )
{
$( 'tbody:visible', topterms_table_element ).last()
.hide()
.trigger( 'change' );
}
);
topterms_navi_more
.die( 'click' )
.live
(
'click',
function( event )
{
$( 'tbody:hidden', topterms_table_element ).first()
if( finfo.topTerms )
{
var topterms = luke_array_to_struct( finfo.topTerms );
var topterms_hash = luke_array_to_hash ( finfo.topTerms );
var topterms_count = topterms.keys.length;
topterms_holder_element.show();
var topterms_table_element = $( 'table', topterms_holder_element );
var topterms_navi_less = $( 'p.navi .less', topterms_holder_element );
var topterms_navi_more = $( 'p.navi .more', topterms_holder_element );
var topterms_content = '<tbody>';
var i = 1;
for( var term in topterms_hash )
{
topterms_content += '<tr>' + "\n" +
'<td class="position">' + i + '</td>' + "\n" +
'<td class="term">' + term + '</td>' + "\n" +
'<td class="frequency">' + topterms_hash[term] + '</td>' + "\n" +
'</tr>' + "\n";
if( i !== topterms_count && 0 === i % 10 )
{
topterms_content += '</tbody><tbody>';
}
i++;
}
topterms_content += '</tbody>';
topterms_table_element
.empty()
.append( topterms_content );
$( 'tbody', topterms_table_element )
.die( 'change' )
.live
(
'change',
function()
{
var blocks = $( 'tbody', topterms_table_element );
var visible_blocks = blocks.filter( ':visible' );
var hidden_blocks = blocks.filter( ':hidden' );
$( 'p.head .shown', topterms_holder_element )
.html( $( 'tr', visible_blocks ).size() );
0 < hidden_blocks.size()
? topterms_navi_more.show()
: topterms_navi_more.hide();
1 < visible_blocks.size()
? topterms_navi_less.show()
: topterms_navi_less.hide();
}
);
$( 'tbody tr:odd', topterms_table_element )
.addClass( 'odd' );
$( 'tbody:first', topterms_table_element )
.show()
.trigger( 'change' );
$( 'p.head .max', topterms_holder_element )
.html( schema_browser_data.fields[field].distinct );
topterms_navi_less
.die( 'click' )
.live
(
'click',
function( event )
{
$( 'tbody:visible', topterms_table_element ).last()
.hide()
.trigger( 'change' );
}
);
topterms_navi_more
.die( 'click' )
.live
(
'click',
function( event )
{
$( 'tbody:hidden', topterms_table_element ).first()
.show()
.trigger( 'change' );
}
);
} // end has Top Terms
}
);
}
else
{
topterms_holder_element
.hide();
}
var histogram_holder_element = $( '.histogram-holder', data_element );
if( is_f && schema_browser_data.fields[field] && schema_browser_data.fields[field].histogram_hash )
{
histogram_holder_element
.show();
var histogram_element = $( '.histogram', histogram_holder_element );
var histogram_values = schema_browser_data.fields[field].histogram_hash;
var histogram_legend = '';
histogram_holder_element
.show();
for( var key in histogram_values )
{
histogram_legend += '<dt><span>' + key + '</span></dt>' + "\n" +
'<dd title="' + key + '">' +
'<span>' + histogram_values[key] + '</span>' +
'</dd>' + "\n";
}
$( 'dl', histogram_holder_element )
.html( histogram_legend );
histogram_element
.sparkline
(
schema_browser_data.fields[field].histogram.values,
{
type : 'bar',
barColor : '#c0c0c0',
zeroColor : '#ffffff',
height : histogram_element.height(),
barWidth : 46,
barSpacing : 3
else {
terminfo_element.hide();
}
);
},
error : function( xhr, text_status, error_thrown)
{
terminfo_element.hide();
},
complete : function( xhr, text_status )
{
}
}
);
}
else
{
histogram_holder_element
.hide();
else {
terminfo_element.hide();
}
}
@ -3870,7 +3915,7 @@ var sammy = $.sammy
$.ajax
(
{
url : core_basepath + '/admin/luke?wt=json',
url : core_basepath + '/admin/luke?wt=json&show=index&numTerms=0',
dataType : 'json',
context : $( '#statistics', dashboard_element ),
beforeSend : function( xhr, settings )
@ -3897,6 +3942,8 @@ var sammy = $.sammy
var data = {
'index_num-docs' : response['index']['numDocs'],
'index_max-doc' : response['index']['maxDoc'],
'index_version' : response['index']['version'],
'index_segmentCount' : response['index']['segmentCount'],
'index_last-modified' : response['index']['lastModified']
};
@ -3910,7 +3957,7 @@ var sammy = $.sammy
}
var optimized_element = $( '.value.index_optimized', this );
if( response['index']['optimized'] )
if( !response['index']['hasDeletions'] )
{
optimized_element
.addClass( 'ico-1' );
@ -3945,20 +3992,6 @@ var sammy = $.sammy
.html( 'no' );
}
var deletions_element = $( '.value.index_has-deletions', this );
if( response['index']['hasDeletions'] )
{
deletions_element.prev()
.show();
deletions_element
.show()
.addClass( 'ico-0' );
$( 'span', deletions_element )
.html( 'yes' );
}
$( 'a', optimized_element )
.die( 'click' )
.live

View File

@ -14,25 +14,28 @@
<dl>
<dt class="index_last-modified">lastModified:</dt>
<dt class="index_last-modified">Last Modified:</dt>
<dd class="index_last-modified value timeago"></dd>
<dt class="index_num-docs">numDocs:</dt>
<dt class="index_num-docs">Num Docs:</dt>
<dd class="index_num-docs value"></dd>
<dt class="index_max-doc">maxDoc:</dt>
<dt class="index_max-doc">Max Doc:</dt>
<dd class="index_max-doc value"></dd>
<dt class="index_optimized">optimized:</dt>
<dt class="index_version">Version:</dt>
<dd class="index_version value"></dd>
<dt class="index_segmentCount">Segment Count:</dt>
<dd class="index_segmentCount value"></dd>
<dt class="index_optimized">Optimized:</dt>
<dd class="index_optimized value ico"><span></span>
<a>optimize now</a></dd>
<dt class="index_current">current:</dt>
<dt class="index_current">Current:</dt>
<dd class="index_current value ico"><span></span></dd>
<dt class="index_has-deletions">deletions:</dt>
<dd class="index_has-deletions value ico"><span></span></dd>
</dl>
</div>

View File

@ -50,7 +50,7 @@
</li>
<li class="clearfix query">
<p>Query Analyzer:</p>
<p>Query&nbsp;Analyzer:</p>
<dl>
<dt></dt>
</dl>
@ -58,13 +58,11 @@
<ul>
<li class="clearfix tokenizer">
<p>Tokenizer:</p>
<dl>
</dl>
<dl></dl>
</li>
<li class="clearfix filters">
<p>Filters:</p>
<dl>
</dl>
<dl></dl>
</li>
</ul>
@ -72,46 +70,50 @@
</ul>
</div>
<div class="topterms-holder">
<p class="head">Top <span class="shown"></span><span class="max-holder">/<span class="max"></span></span> Terms:</p>
<table border="0" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th class="position" title="Position">&nbsp;</th>
<th class="term">Term</th>
<th class="frequency" title="Frequency">Frq</th>
</tr>
</thead>
</table>
<p class="navi clearfix">
<a class="less"><span>less</span></a>
<a class="more"><span>more</span></a>
</p>
</div>
<div class="histogram-holder">
<p class="head">Histogram:</p>
<div class="histogram"></div>
<dl class="clearfix">
</dl>
<div class="terminfo-holder">
<div class="status-holder">Load Term Info</div>
<div class="topterms-holder">
<p class="head">Top <span class="shown"></span><span class="max-holder">/<span class="max"></span></span> Terms:</p>
<table border="0" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th class="position" title="Position">&nbsp;</th>
<th class="term">Term</th>
<th class="frequency" title="Frequency">Frq</th>
</tr>
</thead>
</table>
<p class="navi clearfix">
<a class="less"><span>less</span></a>
<a class="more"><span>more</span></a>
</p>
</div>
<div class="histogram-holder">
<p class="head">Histogram:</p>
<div class="histogram"></div>
<dl class="clearfix">
</dl>
</div>
</div>
</div>
</div>