2
votes

I am trying to get an aggregate query to run using the ML Java API, and am having a bit of trouble. I have followed the documentation, but there is a requirement for a values constraint, and i'm not really sure what that is supposed to look like. I tried the following:

    String options =
            "<options xmlns:search=\"http://marklogic.com/appservices/search\">" +
            "   <values name=\"average\">" +
            "       <range type=\"xs:string\">" +
            "           <element ns=\"\" name=\"content-id\"/>" +
            "       </range>" +
            "   </values>" +
            "</options>";

    StringHandle handle = new StringHandle(options);
    QueryOptionsManager optMgr = client.newServerConfigManager().newQueryOptionsManager();
    optMgr.writeOptions("average", handle);
    QueryManager queryManager = client.newQueryManager();
    StructuredQueryBuilder queryBuilder = queryManager.newStructuredQueryBuilder();
    ValuesDefinition valuesDefinition = queryManager.newValuesDefinition("average");
    valuesDefinition.setAggregate("avg");
    valuesDefinition.setQueryDefinition(queryBuilder.value(queryBuilder.element("content-id"),contentId));

    ValuesHandle results = queryManager.values(valuesDefinition, new ValuesHandle());

I took a stab at the options based on some other options i'm using. However, when I try to write the options it tells me Invalid Content: Unexpected Payload.

I get the feeling i'm going about this the wrong way. Essentially I want to find all documents that have a given value in the element "content-id", and then get the average of another element called "star-rating".

Should the options be set for "content-id" or "star-rating"? The documentation doesn't show the use of a queryDefinition, should I remove that? Modify it? Is there an easier way to do this in Java?

Edit: Forgot to mention, I also created an element range index on content-id with type string.

1
You're right to add setQueryDefinition to filter on "content-id". However, you don't need to use options to filter by a given value in "content-id". Just use queryBuilder.range() rather than queryBuilder.value(). You do need "star-rating" in your options under <values> and your valuesDefinition should center around that. - Sam Mefford
@SamMefford I changed to range() and modified the options and put star-rating in instead of content-id, but I am getting an error saying Invalid parameter: No values or tuples specification named: star-rating - fun_hat
Tried Googling the error but i'm not getting anything - fun_hat
@SamMefford never-mind my above comment. It was a dumb mistake of forgetting to add the options name to the query builder. It appears to be working now. Thanks! - fun_hat

1 Answers

2
votes

With the guidance of @SamMefford I was able to reach a solution. It looks like this:

    String options =
            "<options xmlns=\"http://marklogic.com/appservices/search\">" +
            "   <values name=\"star-rating\">" +
            "       <range type=\"xs:float\">" +
            "           <element ns=\"\" name=\"star-rating\"/>" +
            "       </range>" +
            "   </values>" +
            "</options>";

    StringHandle handle = new StringHandle(options);
    QueryOptionsManager optMgr = client.newServerConfigManager().newQueryOptionsManager();
    optMgr.writeOptions("star-rating", handle);
    QueryManager queryManager = client.newQueryManager();
    StructuredQueryBuilder queryBuilder = 
        queryManager.newStructuredQueryBuilder("star-rating");
    ValuesDefinition valuesDefinition = queryManager.newValuesDefinition("star-rating");
    valuesDefinition.setAggregate("avg");
    valuesDefinition.setQueryDefinition(
        queryBuilder.range(
            queryBuilder.element("content-id"),"string", 
            StructuredQueryBuilder.Operator.EQ,contentId
        )
    );

    String results = queryManager.values(valuesDefinition, new ValuesHandle())
       .getAggregate("avg").getValue();

The options were created around the field that I wanted the average of. I created element indexes for both < star-rating > and < content-id >. The query then allowed me to filter to records with a specific content-id, and then get the average value of their star-ratings.