LUCENE-2343: add support for benchmarking collectors

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@927178 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Grant Ingersoll 2010-03-24 20:49:44 +00:00
parent 03216a150e
commit eb6e13fe9e
6 changed files with 463 additions and 122 deletions

View File

@ -2,7 +2,10 @@ Lucene Benchmark Contrib Change Log
The Benchmark contrib package contains code for benchmarking Lucene in a variety of ways. The Benchmark contrib package contains code for benchmarking Lucene in a variety of ways.
2/21/2020 3/24/2010
LUCENE-2343: Added support for benchmarking collectors. (Grant Ingersoll, Shai Erera)
2/21/2010
LUCENE-2254: Add support to the quality package for running LUCENE-2254: Add support to the quality package for running
experiments with any combination of Title, Description, and Narrative. experiments with any combination of Title, Description, and Narrative.
(Robert Muir) (Robert Muir)

View File

@ -0,0 +1,91 @@
#/**
# * 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.
# */
# -------------------------------------------------------------------------------------
# multi val params are iterated by NewRound's, added to reports, start with column name.
# collector.class can be:
# Fully Qualified Class Name of a Collector with a empty constructor
# topScoreDocOrdered - Creates a TopScoreDocCollector that requires in order docs
# topScoreDocUnordered - Like above, but allows out of order
collector.class=coll:topScoreDocOrdered:topScoreDocUnordered:topScoreDocOrdered:topScoreDocUnordered
analyzer=org.apache.lucene.analysis.WhitespaceAnalyzer
directory=FSDirectory
#directory=RamDirectory
doc.stored=true
doc.tokenized=true
doc.term.vector=false
log.step=100000
search.num.hits=100000
content.source=org.apache.lucene.benchmark.byTask.feeds.LongToEnglishContentSource
query.maker=org.apache.lucene.benchmark.byTask.feeds.LongToEnglishQueryMaker
# task at this depth or less would print when they start
task.max.depth.log=2
log.queries=true
# -------------------------------------------------------------------------------------
{ "Rounds"
ResetSystemErase
{ "Populate"
CreateIndex
{ "MAddDocs" AddDoc } : 200000
Optimize
CloseIndex
}
OpenReader
{ "topDocs" SearchWithCollector > : 10
CloseReader
# OpenReader
#uses an array of search.num.hits size, but can also take in a parameter
# { "psc" SearchWithPostSortCollector > : 10
# { "psc100" SearchWithPostSortCollector(100) > : 10
# { "psc1000" SearchWithPostSortCollector(1000) > : 10
# { "psc10000" SearchWithPostSortCollector(10000) > : 10
# { "psc50000" SearchWithPostSortCollector(50000) > : 10
# CloseReader
RepSumByPref topDocs
# RepSumByPref psc
# RepSumByPref psc100
# RepSumByPref psc1000
# RepSumByPref psc10000
# RepSumByPref psc50000
NewRound
} : 4
#RepSumByNameRound
#RepSumByName
#RepSumByPrefRound topDocs
#RepSumByPrefRound psc
#RepSumByPrefRound psc100
#RepSumByPrefRound psc1000
#RepSumByPrefRound psc10000
#RepSumByPrefRound psc50000

View File

@ -0,0 +1,91 @@
#/**
# * 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.
# */
# -------------------------------------------------------------------------------------
# multi val params are iterated by NewRound's, added to reports, start with column name.
# collector.class can be:
# Fully Qualified Class Name of a Collector with a empty constructor
# topScoreDocOrdered - Creates a TopScoreDocCollector that requires in order docs
# topScoreDocUnordered - Like above, but allows out of order
collector.class=coll:topScoreDocOrdered:topScoreDocUnordered:topScoreDocOrdered:topScoreDocUnordered
analyzer=org.apache.lucene.analysis.WhitespaceAnalyzer
directory=FSDirectory
#directory=RamDirectory
doc.stored=true
doc.tokenized=true
doc.term.vector=false
log.step=100000
search.num.hits=1000000
content.source=org.apache.lucene.benchmark.byTask.feeds.LongToEnglishContentSource
query.maker=org.apache.lucene.benchmark.byTask.feeds.LongToEnglishQueryMaker
# task at this depth or less would print when they start
task.max.depth.log=2
log.queries=true
# -------------------------------------------------------------------------------------
{ "Rounds"
ResetSystemErase
{ "Populate"
CreateIndex
{ "MAddDocs" AddDoc } : 2000000
Optimize
CloseIndex
}
OpenReader
{ "topDocs" SearchWithCollector > : 10
CloseReader
# OpenReader
#uses an array of search.num.hits size, but can also take in a parameter
# { "psc" SearchWithPostSortCollector > : 10
# { "psc100" SearchWithPostSortCollector(100) > : 10
# { "psc1000" SearchWithPostSortCollector(1000) > : 10
# { "psc10000" SearchWithPostSortCollector(10000) > : 10
# { "psc50000" SearchWithPostSortCollector(50000) > : 10
# CloseReader
RepSumByPref topDocs
# RepSumByPref psc
# RepSumByPref psc100
# RepSumByPref psc1000
# RepSumByPref psc10000
# RepSumByPref psc50000
NewRound
} : 4
#RepSumByNameRound
#RepSumByName
#RepSumByPrefRound topDocs
#RepSumByPrefRound psc
#RepSumByPrefRound psc100
#RepSumByPrefRound psc1000
#RepSumByPrefRound psc10000
#RepSumByPrefRound psc50000

View File

@ -30,10 +30,12 @@ import org.apache.lucene.benchmark.byTask.feeds.QueryMaker;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.document.Fieldable; import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.TopFieldCollector; import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.search.Weight; import org.apache.lucene.search.Weight;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
@ -105,23 +107,29 @@ public abstract class ReadTask extends PerfTask {
res++; res++;
Query q = queryMaker.makeQuery(); Query q = queryMaker.makeQuery();
Sort sort = getSort(); Sort sort = getSort();
TopDocs hits; TopDocs hits = null;
final int numHits = numHits(); final int numHits = numHits();
if (numHits > 0) { if (numHits > 0) {
if (sort != null) { if (withCollector() == false) {
Weight w = q.weight(searcher); if (sort != null) {
TopFieldCollector collector = TopFieldCollector.create(sort, numHits, Weight w = q.weight(searcher);
true, withScore(), TopFieldCollector collector = TopFieldCollector.create(sort, numHits,
withMaxScore(), true, withScore(),
!w.scoresDocsOutOfOrder()); withMaxScore(),
searcher.search(w, null, collector); !w.scoresDocsOutOfOrder());
hits = collector.topDocs(); searcher.search(w, null, collector);
hits = collector.topDocs();
} else {
hits = searcher.search(q, numHits);
}
} else { } else {
hits = searcher.search(q, numHits); Collector collector = createCollector();
searcher.search(q, null, collector);
//hits = collector.topDocs();
} }
final String printHitsField = getRunData().getConfig().get("print.hits.field", null); final String printHitsField = getRunData().getConfig().get("print.hits.field", null);
if (printHitsField != null && printHitsField.length() > 0) { if (hits != null && printHitsField != null && printHitsField.length() > 0) {
if (q instanceof MultiTermQuery) { if (q instanceof MultiTermQuery) {
System.out.println("MultiTermQuery term count = " + ((MultiTermQuery) q).getTotalNumberOfTerms()); System.out.println("MultiTermQuery term count = " + ((MultiTermQuery) q).getTotalNumberOfTerms());
} }
@ -177,6 +185,9 @@ public abstract class ReadTask extends PerfTask {
return res; return res;
} }
protected Collector createCollector() throws Exception {
return TopScoreDocCollector.create(numHits(), true);
}
protected Document retrieveDoc(IndexReader ir, int id) throws IOException { protected Document retrieveDoc(IndexReader ir, int id) throws IOException {
@ -192,6 +203,10 @@ public abstract class ReadTask extends PerfTask {
* Return true if search should be performed. * Return true if search should be performed.
*/ */
public abstract boolean withSearch(); public abstract boolean withSearch();
public boolean withCollector(){
return false;
}
/** /**

View File

@ -0,0 +1,95 @@
package org.apache.lucene.benchmark.byTask.tasks;
/**
* 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.
*/
import org.apache.lucene.benchmark.byTask.PerfRunData;
import org.apache.lucene.benchmark.byTask.feeds.QueryMaker;
import org.apache.lucene.benchmark.byTask.utils.Config;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.TopScoreDocCollector;
import java.io.IOException;
/**
* Does search w/ a custom collector
*/
public class SearchWithCollectorTask extends SearchTask {
protected String clnName;
public SearchWithCollectorTask(PerfRunData runData) {
super(runData);
}
@Override
public void setup() throws Exception {
super.setup();
//check to make sure either the doc is being stored
PerfRunData runData = getRunData();
Config config = runData.getConfig();
clnName = config.get("collector.class", "");
}
@Override
public boolean withCollector() {
return true;
}
@Override
protected Collector createCollector() throws Exception {
Collector collector = null;
if (clnName.equalsIgnoreCase("topScoreDocOrdered") == true) {
collector = TopScoreDocCollector.create(numHits(), true);
} else if (clnName.equalsIgnoreCase("topScoreDocUnOrdered") == true) {
collector = TopScoreDocCollector.create(numHits(), false);
} else if (clnName.length() > 0){
collector = Class.forName(clnName).asSubclass(Collector.class).newInstance();
} else {
collector = super.createCollector();
}
return collector;
}
@Override
public QueryMaker getQueryMaker() {
return getRunData().getQueryMaker(this);
}
@Override
public boolean withRetrieve() {
return false;
}
@Override
public boolean withSearch() {
return true;
}
@Override
public boolean withTraverse() {
return false;
}
@Override
public boolean withWarm() {
return false;
}
}

View File

@ -22,20 +22,20 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
/** /**
* Perf run configuration properties. * Perf run configuration properties.
* <p> * <p/>
* Numeric property containing ":", e.g. "10:100:5" is interpreted * Numeric property containing ":", e.g. "10:100:5" is interpreted
* as array of numeric values. It is extracted once, on first use, and * as array of numeric values. It is extracted once, on first use, and
* maintain a round number to return the appropriate value. * maintain a round number to return the appropriate value.
* <p> * <p/>
* The config property "work.dir" tells where is the root of * The config property "work.dir" tells where is the root of
* docs data dirs and indexes dirs. It is set to either of: <ul> * docs data dirs and indexes dirs. It is set to either of: <ul>
* <li>value supplied for it in the alg file;</li> * <li>value supplied for it in the alg file;</li>
* <li>otherwise, value of System property "benchmark.work.dir";</li> * <li>otherwise, value of System property "benchmark.work.dir";</li>
@ -48,30 +48,31 @@ public class Config {
private int roundNumber = 0; private int roundNumber = 0;
private Properties props; private Properties props;
private HashMap<String,Object> valByRound = new HashMap<String,Object>(); private HashMap<String, Object> valByRound = new HashMap<String, Object>();
private HashMap<String,String> colForValByRound = new HashMap<String,String>(); private HashMap<String, String> colForValByRound = new HashMap<String, String>();
private String algorithmText; private String algorithmText;
/** /**
* Read both algorithm and config properties. * Read both algorithm and config properties.
*
* @param algReader from where to read algorithm and config properties. * @param algReader from where to read algorithm and config properties.
* @throws IOException * @throws IOException
*/ */
public Config (Reader algReader) throws IOException { public Config(Reader algReader) throws IOException {
// read alg file to array of lines // read alg file to array of lines
ArrayList<String> lines = new ArrayList<String>(); ArrayList<String> lines = new ArrayList<String>();
BufferedReader r = new BufferedReader(algReader); BufferedReader r = new BufferedReader(algReader);
int lastConfigLine=0; int lastConfigLine = 0;
for (String line = r.readLine(); line!=null; line=r.readLine()) { for (String line = r.readLine(); line != null; line = r.readLine()) {
lines.add(line); lines.add(line);
if (line.indexOf('=')>0) { if (line.indexOf('=') > 0) {
lastConfigLine = lines.size(); lastConfigLine = lines.size();
} }
} }
r.close(); r.close();
// copy props lines to string // copy props lines to string
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (int i=0; i<lastConfigLine; i++) { for (int i = 0; i < lastConfigLine; i++) {
sb.append(lines.get(i)); sb.append(lines.get(i));
sb.append(NEW_LINE); sb.append(NEW_LINE);
} }
@ -80,17 +81,17 @@ public class Config {
props.load(new ByteArrayInputStream(sb.toString().getBytes())); props.load(new ByteArrayInputStream(sb.toString().getBytes()));
// make sure work dir is set properly // make sure work dir is set properly
if (props.get("work.dir")==null) { if (props.get("work.dir") == null) {
props.setProperty("work.dir",System.getProperty("benchmark.work.dir","work")); props.setProperty("work.dir", System.getProperty("benchmark.work.dir", "work"));
} }
if (Boolean.valueOf(props.getProperty("print.props","true")).booleanValue()) { if (Boolean.valueOf(props.getProperty("print.props", "true")).booleanValue()) {
printProps(); printProps();
} }
// copy algorithm lines // copy algorithm lines
sb = new StringBuffer(); sb = new StringBuffer();
for (int i=lastConfigLine; i<lines.size(); i++) { for (int i = lastConfigLine; i < lines.size(); i++) {
sb.append(lines.get(i)); sb.append(lines.get(i));
sb.append(NEW_LINE); sb.append(NEW_LINE);
} }
@ -121,147 +122,176 @@ public class Config {
/** /**
* Return a string property. * Return a string property.
*
* @param name name of property. * @param name name of property.
* @param dflt default value. * @param dflt default value.
* @return a string property. * @return a string property.
*/ */
public String get (String name, String dflt) { public String get(String name, String dflt) {
return props.getProperty(name,dflt); String vals[] = (String[]) valByRound.get(name);
if (vals != null) {
return vals[roundNumber % vals.length];
}
// done if not by round
String sval = props.getProperty(name, dflt);
if (sval == null) {
return null;
}
if (sval.indexOf(":") < 0) {
return sval;
}
// first time this prop is extracted by round
int k = sval.indexOf(":");
String colName = sval.substring(0, k);
sval = sval.substring(k + 1);
colForValByRound.put(name, colName);
vals = propToStringArray(sval);
valByRound.put(name, vals);
return vals[roundNumber % vals.length];
} }
/** /**
* Set a property. * Set a property.
* Note: once a multiple values property is set, it can no longer be modified. * Note: once a multiple values property is set, it can no longer be modified.
* @param name name of property. *
* @param name name of property.
* @param value either single or multiple property value (multiple values are separated by ":") * @param value either single or multiple property value (multiple values are separated by ":")
* @throws Exception * @throws Exception
*/ */
public void set (String name, String value) throws Exception { public void set(String name, String value) throws Exception {
if (valByRound.get(name) != null) { if (valByRound.get(name) != null) {
throw new Exception("Cannot modify a multi value property!"); throw new Exception("Cannot modify a multi value property!");
} }
props.setProperty(name,value); props.setProperty(name, value);
} }
/** /**
* Return an int property. * Return an int property.
* If the property contain ":", e.g. "10:100:5", it is interpreted * If the property contain ":", e.g. "10:100:5", it is interpreted
* as array of ints. It is extracted once, on first call * as array of ints. It is extracted once, on first call
* to get() it, and a by-round-value is returned. * to get() it, and a by-round-value is returned.
*
* @param name name of property * @param name name of property
* @param dflt default value * @param dflt default value
* @return a int property. * @return a int property.
*/ */
public int get (String name, int dflt) { public int get(String name, int dflt) {
// use value by round if already parsed // use value by round if already parsed
int vals[] = (int[]) valByRound.get(name); int vals[] = (int[]) valByRound.get(name);
if (vals != null) { if (vals != null) {
return vals[roundNumber % vals.length]; return vals[roundNumber % vals.length];
} }
// done if not by round // done if not by round
String sval = props.getProperty(name,""+dflt); String sval = props.getProperty(name, "" + dflt);
if (sval.indexOf(":")<0) { if (sval.indexOf(":") < 0) {
return Integer.parseInt(sval); return Integer.parseInt(sval);
} }
// first time this prop is extracted by round // first time this prop is extracted by round
int k = sval.indexOf(":"); int k = sval.indexOf(":");
String colName = sval.substring(0,k); String colName = sval.substring(0, k);
sval = sval.substring(k+1); sval = sval.substring(k + 1);
colForValByRound.put(name,colName); colForValByRound.put(name, colName);
vals = propToIntArray(sval); vals = propToIntArray(sval);
valByRound.put(name,vals); valByRound.put(name, vals);
return vals[roundNumber % vals.length]; return vals[roundNumber % vals.length];
} }
/** /**
* Return a double property. * Return a double property.
* If the property contain ":", e.g. "10:100:5", it is interpreted * If the property contain ":", e.g. "10:100:5", it is interpreted
* as array of doubles. It is extracted once, on first call * as array of doubles. It is extracted once, on first call
* to get() it, and a by-round-value is returned. * to get() it, and a by-round-value is returned.
*
* @param name name of property * @param name name of property
* @param dflt default value * @param dflt default value
* @return a double property. * @return a double property.
*/ */
public double get (String name, double dflt) { public double get(String name, double dflt) {
// use value by round if already parsed // use value by round if already parsed
double vals[] = (double[]) valByRound.get(name); double vals[] = (double[]) valByRound.get(name);
if (vals != null) { if (vals != null) {
return vals[roundNumber % vals.length]; return vals[roundNumber % vals.length];
} }
// done if not by round // done if not by round
String sval = props.getProperty(name,""+dflt); String sval = props.getProperty(name, "" + dflt);
if (sval.indexOf(":")<0) { if (sval.indexOf(":") < 0) {
return Double.parseDouble(sval); return Double.parseDouble(sval);
} }
// first time this prop is extracted by round // first time this prop is extracted by round
int k = sval.indexOf(":"); int k = sval.indexOf(":");
String colName = sval.substring(0,k); String colName = sval.substring(0, k);
sval = sval.substring(k+1); sval = sval.substring(k + 1);
colForValByRound.put(name,colName); colForValByRound.put(name, colName);
vals = propToDoubleArray(sval); vals = propToDoubleArray(sval);
valByRound.put(name,vals); valByRound.put(name, vals);
return vals[roundNumber % vals.length]; return vals[roundNumber % vals.length];
} }
/** /**
* Return a boolean property. * Return a boolean property.
* If the property contain ":", e.g. "true.true.false", it is interpreted * If the property contain ":", e.g. "true.true.false", it is interpreted
* as array of booleans. It is extracted once, on first call * as array of booleans. It is extracted once, on first call
* to get() it, and a by-round-value is returned. * to get() it, and a by-round-value is returned.
*
* @param name name of property * @param name name of property
* @param dflt default value * @param dflt default value
* @return a int property. * @return a int property.
*/ */
public boolean get (String name, boolean dflt) { public boolean get(String name, boolean dflt) {
// use value by round if already parsed // use value by round if already parsed
boolean vals[] = (boolean[]) valByRound.get(name); boolean vals[] = (boolean[]) valByRound.get(name);
if (vals != null) { if (vals != null) {
return vals[roundNumber % vals.length]; return vals[roundNumber % vals.length];
} }
// done if not by round // done if not by round
String sval = props.getProperty(name,""+dflt); String sval = props.getProperty(name, "" + dflt);
if (sval.indexOf(":")<0) { if (sval.indexOf(":") < 0) {
return Boolean.valueOf(sval).booleanValue(); return Boolean.valueOf(sval).booleanValue();
} }
// first time this prop is extracted by round // first time this prop is extracted by round
int k = sval.indexOf(":"); int k = sval.indexOf(":");
String colName = sval.substring(0,k); String colName = sval.substring(0, k);
sval = sval.substring(k+1); sval = sval.substring(k + 1);
colForValByRound.put(name,colName); colForValByRound.put(name, colName);
vals = propToBooleanArray(sval); vals = propToBooleanArray(sval);
valByRound.put(name,vals); valByRound.put(name, vals);
return vals[roundNumber % vals.length]; return vals[roundNumber % vals.length];
} }
/** /**
* Increment the round number, for config values that are extracted by round number. * Increment the round number, for config values that are extracted by round number.
*
* @return the new round number. * @return the new round number.
*/ */
public int newRound () { public int newRound() {
roundNumber++; roundNumber++;
StringBuffer sb = new StringBuffer("--> Round ").append(roundNumber-1).append("-->").append(roundNumber); StringBuffer sb = new StringBuffer("--> Round ").append(roundNumber - 1).append("-->").append(roundNumber);
// log changes in values // log changes in values
if (valByRound.size()>0) { if (valByRound.size() > 0) {
sb.append(": "); sb.append(": ");
for (final String name : valByRound.keySet()) { for (final String name : valByRound.keySet()) {
Object a = valByRound.get(name); Object a = valByRound.get(name);
if (a instanceof int[]) { if (a instanceof int[]) {
int ai[] = (int[]) a; int ai[] = (int[]) a;
int n1 = (roundNumber-1)%ai.length; int n1 = (roundNumber - 1) % ai.length;
int n2 = roundNumber%ai.length; int n2 = roundNumber % ai.length;
sb.append(" ").append(name).append(":").append(ai[n1]).append("-->").append(ai[n2]); sb.append(" ").append(name).append(":").append(ai[n1]).append("-->").append(ai[n2]);
} else if (a instanceof double[]){ } else if (a instanceof double[]) {
double ad[] = (double[]) a; double ad[] = (double[]) a;
int n1 = (roundNumber-1)%ad.length; int n1 = (roundNumber - 1) % ad.length;
int n2 = roundNumber%ad.length; int n2 = roundNumber % ad.length;
sb.append(" ").append(name).append(":").append(ad[n1]).append("-->").append(ad[n2]); sb.append(" ").append(name).append(":").append(ad[n1]).append("-->").append(ad[n2]);
} } else if (a instanceof String[]) {
else { String ad[] = (String[]) a;
int n1 = (roundNumber - 1) % ad.length;
int n2 = roundNumber % ad.length;
sb.append(" ").append(name).append(":").append(ad[n1]).append("-->").append(ad[n2]);
} else {
boolean ab[] = (boolean[]) a; boolean ab[] = (boolean[]) a;
int n1 = (roundNumber-1)%ab.length; int n1 = (roundNumber - 1) % ab.length;
int n2 = roundNumber%ab.length; int n2 = roundNumber % ab.length;
sb.append(" ").append(name).append(":").append(ab[n1]).append("-->").append(ab[n2]); sb.append(" ").append(name).append(":").append(ab[n1]).append("-->").append(ab[n2]);
} }
} }
@ -270,62 +300,76 @@ public class Config {
System.out.println(); System.out.println();
System.out.println(sb.toString()); System.out.println(sb.toString());
System.out.println(); System.out.println();
return roundNumber; return roundNumber;
} }
// extract properties to array, e.g. for "10:100:5" return int[]{10,100,5}. private String[] propToStringArray(String s) {
private int[] propToIntArray (String s) { if (s.indexOf(":") < 0) {
if (s.indexOf(":")<0) { return new String[]{s};
return new int [] { Integer.parseInt(s) };
} }
ArrayList<String> a = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(s, ":");
while (st.hasMoreTokens()) {
String t = st.nextToken();
a.add(t);
}
return (String[]) a.toArray(new String[a.size()]);
}
// extract properties to array, e.g. for "10:100:5" return int[]{10,100,5}.
private int[] propToIntArray(String s) {
if (s.indexOf(":") < 0) {
return new int[]{Integer.parseInt(s)};
}
ArrayList<Integer> a = new ArrayList<Integer>(); ArrayList<Integer> a = new ArrayList<Integer>();
StringTokenizer st = new StringTokenizer(s,":"); StringTokenizer st = new StringTokenizer(s, ":");
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String t = st.nextToken(); String t = st.nextToken();
a.add(Integer.valueOf(t)); a.add(Integer.valueOf(t));
} }
int res[] = new int[a.size()]; int res[] = new int[a.size()];
for (int i=0; i<a.size(); i++) { for (int i = 0; i < a.size(); i++) {
res[i] = a.get(i).intValue(); res[i] = a.get(i).intValue();
} }
return res; return res;
} }
// extract properties to array, e.g. for "10.7:100.4:-2.3" return int[]{10.7,100.4,-2.3}. // extract properties to array, e.g. for "10.7:100.4:-2.3" return int[]{10.7,100.4,-2.3}.
private double[] propToDoubleArray (String s) { private double[] propToDoubleArray(String s) {
if (s.indexOf(":")<0) { if (s.indexOf(":") < 0) {
return new double [] { Double.parseDouble(s) }; return new double[]{Double.parseDouble(s)};
} }
ArrayList<Double> a = new ArrayList<Double>(); ArrayList<Double> a = new ArrayList<Double>();
StringTokenizer st = new StringTokenizer(s,":"); StringTokenizer st = new StringTokenizer(s, ":");
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String t = st.nextToken(); String t = st.nextToken();
a.add(Double.valueOf(t)); a.add(Double.valueOf(t));
} }
double res[] = new double[a.size()]; double res[] = new double[a.size()];
for (int i=0; i<a.size(); i++) { for (int i = 0; i < a.size(); i++) {
res[i] = a.get(i).doubleValue(); res[i] = a.get(i).doubleValue();
} }
return res; return res;
} }
// extract properties to array, e.g. for "true:true:false" return boolean[]{true,false,false}. // extract properties to array, e.g. for "true:true:false" return boolean[]{true,false,false}.
private boolean[] propToBooleanArray (String s) { private boolean[] propToBooleanArray(String s) {
if (s.indexOf(":")<0) { if (s.indexOf(":") < 0) {
return new boolean [] { Boolean.valueOf(s).booleanValue() }; return new boolean[]{Boolean.valueOf(s).booleanValue()};
} }
ArrayList<Boolean> a = new ArrayList<Boolean>(); ArrayList<Boolean> a = new ArrayList<Boolean>();
StringTokenizer st = new StringTokenizer(s,":"); StringTokenizer st = new StringTokenizer(s, ":");
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String t = st.nextToken(); String t = st.nextToken();
a.add(new Boolean(t)); a.add(new Boolean(t));
} }
boolean res[] = new boolean[a.size()]; boolean res[] = new boolean[a.size()];
for (int i=0; i<a.size(); i++) { for (int i = 0; i < a.size(); i++) {
res[i] = a.get(i).booleanValue(); res[i] = a.get(i).booleanValue();
} }
return res; return res;
@ -335,10 +379,10 @@ public class Config {
* @return names of params set by round, for reports title * @return names of params set by round, for reports title
*/ */
public String getColsNamesForValsByRound() { public String getColsNamesForValsByRound() {
if (colForValByRound.size()==0) { if (colForValByRound.size() == 0) {
return ""; return "";
} }
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (final String name : colForValByRound.keySet()) { for (final String name : colForValByRound.keySet()) {
String colName = colForValByRound.get(name); String colName = colForValByRound.get(name);
sb.append(" ").append(colName); sb.append(" ").append(colName);
@ -350,33 +394,35 @@ public class Config {
* @return values of params set by round, for reports lines. * @return values of params set by round, for reports lines.
*/ */
public String getColsValuesForValsByRound(int roundNum) { public String getColsValuesForValsByRound(int roundNum) {
if (colForValByRound.size()==0) { if (colForValByRound.size() == 0) {
return ""; return "";
} }
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
for (final String name : colForValByRound.keySet()) { for (final String name : colForValByRound.keySet()) {
String colName = colForValByRound.get(name); String colName = colForValByRound.get(name);
String template = " "+colName; String template = " " + colName;
if (roundNum<0) { if (roundNum < 0) {
// just append blanks // just append blanks
sb.append(Format.formatPaddLeft("-",template)); sb.append(Format.formatPaddLeft("-", template));
} else { } else {
// append actual values, for that round // append actual values, for that round
Object a = valByRound.get(name); Object a = valByRound.get(name);
if (a instanceof int[]) { if (a instanceof int[]) {
int ai[] = (int[]) a; int ai[] = (int[]) a;
int n = roundNum % ai.length; int n = roundNum % ai.length;
sb.append(Format.format(ai[n],template)); sb.append(Format.format(ai[n], template));
} } else if (a instanceof double[]) {
else if (a instanceof double[]) {
double ad[] = (double[]) a; double ad[] = (double[]) a;
int n = roundNum % ad.length; int n = roundNum % ad.length;
sb.append(Format.format(2, ad[n],template)); sb.append(Format.format(2, ad[n], template));
} } else if (a instanceof String[]) {
else { String ad[] = (String[]) a;
int n = roundNum % ad.length;
sb.append(ad[n]);
} else {
boolean ab[] = (boolean[]) a; boolean ab[] = (boolean[]) a;
int n = roundNum % ab.length; int n = roundNum % ab.length;
sb.append(Format.formatPaddLeft(""+ab[n],template)); sb.append(Format.formatPaddLeft("" + ab[n], template));
} }
} }
} }