Skip to content

Conversation

mmiguerodriguez
Copy link
Collaborator

@mmiguerodriguez mmiguerodriguez commented Aug 25, 2025

This branch extends EvoMaster with distance calculation support for OpenSearch queries.

Features

  • Added OPENSEARCH to Heuristic DTO Entry type.

Distance Data Structures

  • OpenSearchDistanceWithMetrics: stores distance and number of evaluated documents (non-negative enforced).
  • OpenSearchCommandWithDistance: pairs commands with their computed distance.

OpenSearchHandler

  • Captures OpenSearch queries during execution.
  • Retrieves documents from indices.
  • Computes query–document distances and records minimum distance + evaluated count.
  • Term Query distance calculation (integers).

Testing

  • Example Age app demonstrating equals and range logic.

@mmiguerodriguez mmiguerodriguez marked this pull request as ready for review August 27, 2025 20:42
@@ -323,6 +327,17 @@ public final void initMongoHandler() {
}
}

public final void initOpenSearchHandler() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is fine in this PR. but, as this code seems very similar to what done for Mongo, maybe @jgaleotti you can refactor it to avoid duplication?
@mmiguerodriguez maybe leave a // TODO comment stating this code likely needs refactoring with the Mongo one

Copy link
Collaborator

@jgaleotti jgaleotti Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please leave a TODO and when the Redis and the OpenSearch implementations are done I will refactor them out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add TODO comment regarding refactors

try {
openSearchHandler.handle(it);
} catch (Exception e){
SimpleLogger.error("FAILED TO HANDLE OPENSEARCH COMMAND");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add info on the error in this log, eg, + e.getMssage()


public final double distance;

public final int numberOfEvaluatedDocuments;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those fields should be private, as anyway you are providing public getters

return calculateDistanceForEquals((TermOperation<?>) operation, doc);
}

return 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it correct to return 0 here? if so, it is not so obvious. add some /* */ comments to clarify it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should be Double.MAX_VALUE as this is the case where it is not supported, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, will modify this.

private final String fieldName;
private final V value;

ComparisonOperation(String fieldName, V value) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default-scope in Java is very tricky, and possibly counter-intuitive. as such, I usually avoid it. consider if a protected makes sense here

Object kind = value.getClass().getMethod("_kind").invoke(value);
String kindName = (String) kind.getClass().getMethod("name").invoke(kind);

switch (kindName) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about Integer and Short?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used OpenSearch FieldValue as reference. Will review if more are required.


public class OpenSearchCommand implements Serializable {
/**
* Name of the index that the operation was applied to
*/
private final Object index;
private final List<String> index;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update docs based on new type. ie, how can a list of strings be a name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this might be confusing, will review how the correct naming should be.
I think that for an initial implementation we should consider only simple Strings, without lists.

} else if (result instanceof String) {
return Collections.singletonList((String) result);
} else {
return Collections.singletonList(result.toString());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this last case expected in normal behaviour? or is it just a safety check to not crash EM? in this latter case, might want to log such event (so we can see when/if it happens, and fix it if needed)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it this way to consider all cases, but the normal behavior would be for the index to be a single String.

return ageRepo.findByAge(age);
}

// @GetMapping("gte/{gte}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this code no longer needed? or to be put back in future? either remove it, or add a TODO comment if you ll need it in future

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be put back when testing other types of queries (eg: Range). Will add TODO comment.


Solution<RestIndividual> solution = initAndRun(args);

// assertHasAtLeastOne(solution, HttpVerb.GET, 404, "/age/{q}", null);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why no assertions? if the techniques work, when you should be able to cover the different endpoints you have designed. if not yet, and tehcniques needs more fixing, it is ok to have a PR now, but: (1) add the needed assertions on the different endpoints; (2) mark the test with @Disabled; (3) leave a TODO comment stating this is failing and need more work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants