Skip to content

Commit

Permalink
Adding running of query set to CLI.
Browse files Browse the repository at this point in the history
  • Loading branch information
jzonthemtn committed Jan 1, 2025
1 parent 41aa00f commit b5d34cf
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 79 deletions.
2 changes: 1 addition & 1 deletion opensearch-search-quality-evaluation-framework/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.opensearch.eval.SearchQualityEvaluationFrameworkApp</mainClass>
<mainClass>org.opensearch.eval.App</mainClass>
</manifest>
</archive>
<descriptorRefs>
Expand Down
10 changes: 10 additions & 0 deletions opensearch-search-quality-evaluation-framework/queryset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"query_set_id": "",
"judgments_id": "",
"index": "",
"search_pipeline": "",
"id_field": "",
"k": 10,
"threshold": 1.0,
"query": {}
}
5 changes: 4 additions & 1 deletion opensearch-search-quality-evaluation-framework/run.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/bin/bash -e

# Create a click model.
java -jar ./target/search-evaluation-framework-1.0.0-SNAPSHOT-jar-with-dependencies.jar -c
java -jar ./target/search-evaluation-framework-1.0.0-SNAPSHOT-jar-with-dependencies.jar -c coec

# Run a query set.
#java -jar ./target/search-evaluation-framework-1.0.0-SNAPSHOT-jar-with-dependencies.jar -r queryset.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,79 @@
*/
package org.opensearch.eval;

import com.google.gson.Gson;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.eval.engine.OpenSearchEngine;
import org.opensearch.eval.engine.SearchEngine;
import org.opensearch.eval.judgments.clickmodel.ClickModel;
import org.opensearch.eval.judgments.clickmodel.coec.CoecClickModel;
import org.opensearch.eval.judgments.clickmodel.coec.CoecClickModelParameters;
import org.opensearch.eval.runners.OpenSearchQuerySetRunner;
import org.opensearch.eval.runners.RunQuerySetParameters;

public class SearchQualityEvaluationFrameworkApp {
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

private static final Logger LOGGER = LogManager.getLogger(SearchQualityEvaluationFrameworkApp.class);
public class App {

private static final Logger LOGGER = LogManager.getLogger(App.class);

public static void main(String[] args) throws Exception {

System.out.println("Search Quality Evaluation Framework");

final Gson gson = new Gson();

final Options options = new Options();
options.addOption("c", false, "create a click model");
options.addOption("q", true, "run a query set");
options.addOption("c", true, "create a click model");
options.addOption("r", true, "run a query set");

final CommandLineParser parser = new DefaultParser();
final CommandLine cmd = parser.parse(options, args);

final SearchEngine searchEngine = new OpenSearchEngine();

if(cmd.hasOption("c")) {

//final String clickModel = cmd.getOptionValue("c");
System.out.println("Creating click model...");

final SearchEngine searchEngine = new OpenSearchEngine();
final CoecClickModelParameters coecClickModelParameters = new CoecClickModelParameters(10);
final String clickModelType = cmd.getOptionValue("c");

if(CoecClickModel.CLICK_MODEL_NAME.equalsIgnoreCase(clickModelType)) {

final CoecClickModelParameters coecClickModelParameters = new CoecClickModelParameters(10);

final ClickModel cm = new CoecClickModel(searchEngine, coecClickModelParameters);
cm.calculateJudgments();

} else {
System.err.println("Invalid click model type. Valid models are 'coec'.");
}

} else if (cmd.hasOption("r")) {

final ClickModel cm = new CoecClickModel(searchEngine, coecClickModelParameters);
cm.calculateJudgments();
System.out.println("Running query set...");

} else {
final String querySetOptionsFile = cmd.getOptionValue("q");
final File file = new File(querySetOptionsFile);

if(file.exists()) {

final RunQuerySetParameters runQuerySetParameters = gson.fromJson(Files.readString(file.toPath(), StandardCharsets.UTF_8), RunQuerySetParameters.class);

final OpenSearchQuerySetRunner openSearchQuerySetRunner = new OpenSearchQuerySetRunner(searchEngine);
openSearchQuerySetRunner.run(runQuerySetParameters);

} else {
System.err.println("The query set run parameters file does not exist.");
}

}

Expand Down Expand Up @@ -123,50 +156,7 @@ public static void main(String[] args) throws Exception {
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.METHOD_NOT_ALLOWED, "{\"error\": \"" + request.method() + " is not allowed.\"}"));
// }
//
// // Handle running query sets.
// } else if(QUERYSET_RUN_URL.equalsIgnoreCase(request.path())) {
//
// final String querySetId = request.param("id");
// final String judgmentsId = request.param("judgments_id");
// final String index = request.param("index");
// final String searchPipeline = request.param("search_pipeline", null);
// final String idField = request.param("id_field", "_id");
// final int k = Integer.parseInt(request.param("k", "10"));
// final double threshold = Double.parseDouble(request.param("threshold", "1.0"));
//
// if(querySetId == null || querySetId.isEmpty() || judgmentsId == null || judgmentsId.isEmpty() || index == null || index.isEmpty()) {
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, "{\"error\": \"Missing required parameters.\"}"));
// }
//
// if(k < 1) {
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, "{\"error\": \"k must be a positive integer.\"}"));
// }
//
// if(!request.hasContent()) {
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, "{\"error\": \"Missing query in body.\"}"));
// }
//
// // Get the query JSON from the content.
// final String query = new String(BytesReference.toBytes(request.content()), Charset.defaultCharset());
//
// // Validate the query has a QUERY_PLACEHOLDER.
// if(!query.contains(QUERY_PLACEHOLDER)) {
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, "{\"error\": \"Missing query placeholder in query.\"}"));
// }
//
// try {
//
// final OpenSearchQuerySetRunner openSearchQuerySetRunner = new OpenSearchQuerySetRunner(client);
// final QuerySetRunResult querySetRunResult = openSearchQuerySetRunner.run(querySetId, judgmentsId, index, searchPipeline, idField, query, k, threshold);
// openSearchQuerySetRunner.save(querySetRunResult);
//
// } catch (Exception ex) {
// LOGGER.error("Unable to run query set. Verify query set and judgments exist.", ex);
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, ex.getMessage()));
// }
//
// return restChannel -> restChannel.sendResponse(new BytesRestResponse(RestStatus.OK, "{\"message\": \"Run initiated for query set " + querySetId + "\"}"));
//

// // Handle the on-demand creation of implicit judgments.
// } else if(IMPLICIT_JUDGMENTS_URL.equalsIgnoreCase(request.path())) {
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,10 @@ public AbstractQuerySetRunner(final SearchEngine searchEngine) {

/**
* Runs the query set.
* @param querySetId The ID of the query set to run.
* @param judgmentsId The ID of the judgments set to use for search metric calculation.
* @param index The name of the index to run the query sets against.
* @param searchPipeline The name of the search pipeline to use, or <code>null</code> to not use a search pipeline.
* @param idField The field in the index that is used to uniquely identify a document.
* @param query The query that will be used to run the query set.
* @param k The k used for metrics calculation, i.e. DCG@k.
* @param threshold The cutoff for binary judgments. A judgment score greater than or equal
* to this value will be assigned a binary judgment value of 1. A judgment score
* less than this value will be assigned a binary judgment value of 0.
* @param querySetParameters A {@link RunQuerySetParameters parameters}.
* @return The query set {@link QuerySetRunResult results} and calculated metrics.
*/
abstract QuerySetRunResult run(String querySetId, final String judgmentsId, final String index, final String searchPipeline,
final String idField, final String query, final int k,
final double threshold) throws Exception;
abstract QuerySetRunResult run(RunQuerySetParameters querySetParameters) throws Exception;

/**
* Saves the query set results to a persistent store, which may be the search engine itself.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ public OpenSearchQuerySetRunner(final SearchEngine searchEngine) {
}

@Override
public QuerySetRunResult run(final String querySetId, final String judgmentsId, final String index,
final String searchPipeline, final String idField, final String query,
final int k, final double threshold) throws Exception {
public QuerySetRunResult run(final RunQuerySetParameters querySetParameters) throws Exception {

final QuerySet querySet = searchEngine.getQuerySet(querySetId);
LOGGER.info("Found {} queries in query set {}", querySet.getQuerySetQueries().size(), querySetId);
final QuerySet querySet = searchEngine.getQuerySet(querySetParameters.getQuerySetId());
LOGGER.info("Found {} queries in query set {}", querySet.getQuerySetQueries().size(), querySetParameters.getQuerySetId());

try {

Expand All @@ -68,23 +66,29 @@ public QuerySetRunResult run(final String querySetId, final String judgmentsId,
// TODO: Look at using the Workload Management in 2.18.0.
Thread.sleep(50);

final List<String> orderedDocumentIds = searchEngine.runQuery(index, query, k, userQuery, idField);
final List<String> orderedDocumentIds = searchEngine.runQuery(
querySetParameters.getIndex(),
querySetParameters.getQuery(),
querySetParameters.getK(),
userQuery,
querySetParameters.getIdField());

try {

final RelevanceScores relevanceScores = getRelevanceScores(judgmentsId, userQuery, orderedDocumentIds, k);
final int k = querySetParameters.getK();
final RelevanceScores relevanceScores = getRelevanceScores(querySetParameters.getJudgmentsId(), userQuery, orderedDocumentIds, k);

// Calculate the metrics for this query.
final SearchMetric dcgSearchMetric = new DcgSearchMetric(k, relevanceScores.getRelevanceScores());
final SearchMetric ndcgSearchmetric = new NdcgSearchMetric(k, relevanceScores.getRelevanceScores());
final SearchMetric precisionSearchMetric = new PrecisionSearchMetric(k, threshold, relevanceScores.getRelevanceScores());
final SearchMetric precisionSearchMetric = new PrecisionSearchMetric(k, querySetParameters.getThreshold(), relevanceScores.getRelevanceScores());

final Collection<SearchMetric> searchMetrics = List.of(dcgSearchMetric, ndcgSearchmetric, precisionSearchMetric);

queryResults.add(new QueryResult(userQuery, orderedDocumentIds, k, searchMetrics, relevanceScores.getFrogs()));

} catch (Exception ex) {
LOGGER.error("Unable to get relevance scores for judgments {} and user query {}.", judgmentsId, userQuery, ex);
LOGGER.error("Unable to get relevance scores for judgments {} and user query {}.", querySetParameters.getJudgmentsId(), userQuery, ex);
}

}
Expand All @@ -110,7 +114,7 @@ public QuerySetRunResult run(final String querySetId, final String judgmentsId,
}

final String querySetRunId = UUID.randomUUID().toString();
final QuerySetRunResult querySetRunResult = new QuerySetRunResult(querySetRunId, querySetId, queryResults, querySetMetrics);
final QuerySetRunResult querySetRunResult = new QuerySetRunResult(querySetRunId, querySetParameters.getQuerySetId(), queryResults, querySetMetrics);

LOGGER.info("Query set run complete: {}", querySetRunId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.opensearch.eval.runners;

import com.google.gson.annotations.SerializedName;

public class RunQuerySetParameters {

@SerializedName("query_set_id")
private String querySetId;

@SerializedName("judgments_id")
private String judgmentsId;

@SerializedName("index")
private String index;

@SerializedName("search_pipeline")
private String searchPipeline;

@SerializedName("id_field")
private String idField;

@SerializedName("query")
private String query;

@SerializedName("k")
private int k;

@SerializedName("threshold")
private double threshold;

// * @param querySetId The ID of the query set to run.
// * @param judgmentsId The ID of the judgments set to use for search metric calculation.
// * @param index The name of the index to run the query sets against.
// * @param searchPipeline The name of the search pipeline to use, or <code>null</code> to not use a search pipeline.
// * @param idField The field in the index that is used to uniquely identify a document.
// * @param query The query that will be used to run the query set.
// * @param k The k used for metrics calculation, i.e. DCG@k.
// * @param threshold The cutoff for binary judgments. A judgment score greater than or equal
// * to this value will be assigned a binary judgment value of 1. A judgment score
// * less than this value will be assigned a binary judgment value of 0.

public String getQuerySetId() {
return querySetId;
}

public void setQuerySetId(String querySetId) {
this.querySetId = querySetId;
}

public String getJudgmentsId() {
return judgmentsId;
}

public void setJudgmentsId(String judgmentsId) {
this.judgmentsId = judgmentsId;
}

public String getIndex() {
return index;
}

public void setIndex(String index) {
this.index = index;
}

public String getSearchPipeline() {
return searchPipeline;
}

public void setSearchPipeline(String searchPipeline) {
this.searchPipeline = searchPipeline;
}

public String getIdField() {
return idField;
}

public void setIdField(String idField) {
this.idField = idField;
}

public String getQuery() {
return query;
}

public void setQuery(String query) {
this.query = query;
}

public int getK() {
return k;
}

public void setK(int k) {
this.k = k;
}

public double getThreshold() {
return threshold;
}

public void setThreshold(double threshold) {
this.threshold = threshold;
}

}

0 comments on commit b5d34cf

Please sign in to comment.