mirror of https://github.com/apache/lucene.git
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:
parent
03216a150e
commit
eb6e13fe9e
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue