Marklogic Aggregate query with Java API - java

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.

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.

Related

Double data type not working with RDF star query

Apache Jena is not able to query RDF Star Triples that have a double data type in them. Here is the code for reproduction of the issue with Jena 3.17 (it can be reproduced on other versions too).
Dataset dataset = TDB2Factory.createDataset();
Model tempModel = ModelFactory.createDefaultModel();
StringReader reader = new StringReader("#prefix : <http://ex#> "
+ "#prefix xsd: <http://www.w3.org/2001/XMLSchema#> "
+ ":rk :val \"1.0\"^^xsd:double ."
+ "<<:rk :val \"1.0\"^^xsd:double>> :p_key 1");
RDFDataMgr.read(tempModel, reader, null, Lang.TURTLE);
dataset.begin(TxnType.WRITE);
Graph repositoryGraph = dataset.getNamedModel("RAW_MODEL").getGraph();
StmtIterator it = tempModel.listStatements();
while(it.hasNext()) {
repositoryGraph.add(it.nextStatement().asTriple());
}
dataset.commit()
dataset.end()
Now during query time, I am using the following code.
dataset.begin(TxnType.READ);
Query query = QueryFactory.create("SELECT ?s ?o ?id WHERE {"
+ "<<?s <http://ex#val> ?o>> <http://ex#p_key> ?id"
+ "}");
try (QueryExecution exec = QueryExecutionFactory.create(query, dataset.getUnionModel())) {
ResultSet result = exec.execSelect();
while (result.hasNext()) {
System.out.println(result.next().toString());
}
}
dataset.end()
The above query fails to fetch any result. However, if I just replace xsd:double with xsd:float or xsd:decimal the results are fetched. Hence, I am looking for help to understand what is causing this issue with xsd:double?
Note: You might think that I am not using the most optimal way to make insertions. However, this was due to other requirements in the code and reproduction of issue is possible through this route.
It works in Jena 4.0.0.
In 3.17.0 - SPARQL was more like the original RDF* in its use of indexing.
As a consequence, the non-canonical term map cause a problem.
Try a lexical form of "1.0e0"^^xsd:double or v 4.x.x.

2 filters with query not working in elasticSearch, java

This is my old code which is working fine
qb = QueryBuilders.queryString(query.replaceAll(" ", " OR ").replaceAll(",", " AND ").replaceAll("!", " NOT "));
FilterBuilder fb = FilterBuilders.andFilter(FilterBuilders.rangeFilter("Experiance").from(smonth).to(emonth));
FilteredQueryBuilder fqBuilder = QueryBuilders.filteredQuery(qb, fb);
org.elasticsearch.action.search.SearchResponse searchHits = node.client()
.prepareSearch(name)
.setQuery(fqBuilder)
In this piece of code, I am searching those data whose experience between smonth and emonth.
Now i need to add more filters in my search, So i move to 'NativeSearchQueryBuilder'. After modification, I write this code:-
qb = QueryBuilders.queryString(query.replaceAll(" ", " OR ").replaceAll(",", " AND ").replaceAll("!", " NOT "));
FilterBuilder fb = FilterBuilders.andFilter(FilterBuilders.rangeFilter("Experiance").from(smonth).to(emonth));
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
builder.withQuery(qb);
AndFilterBuilder filters = null;
filters = new AndFilterBuilder(fb);
filters.add(FilterBuilders.andFilter(FilterBuilders.boolFilter().must(FilterBuilders.termFilter("providedZipcode", zipcode)))); //third filter
builder.withFilter(filters);
org.elasticsearch.action.search.SearchResponse searchHits = node.client()
.prepareSearch(name)
.setQuery(builder.build().getQuery());
But when i am searching then filter is not working. I am not getting data according to experience and zipcode.
Got it.
We can use setPostFilter
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/search.html
org.elasticsearch.action.search.SearchResponse searchHits = node.client()
.prepareSearch(name)
// .setIndices(name)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(fqBuilder)
.setPostFilter(FilterBuilders.andFilter(FilterBuilders.boolFilter().must(FilterBuilders.termFilter("providedZipcode", zipcode)))); // Filter
But i have another problem. If i didnt pass zipcode then it's not showing data. I want to get all data if i not pass any zipcode.
You look like you would actually benefit more from using a bool filter, with two condiditons in addition to the query string. We will be searching all documents that hopefully match the providedZipcode but definitely have experience ranging from smonth to emonth. In my answer, I used a bool filter to implement this logic.
Post Filter in your above answer isn't really the functionality that you are looking for. It executes your request using the original query, and then filters the results of that original query by the second filter.
This is how I wrote up your request:
QueryStringQueryBuilder qb = QueryBuilders.queryString(query
.replaceAll(" ", " OR ")
.replaceAll(",", " AND ")
.replaceAll("!", " NOT "));
FilterBuilder fb = FilterBuilders.boolFilter()
.should(FilterBuilders.termFilter("providedZipcode", zipcode))
.must(FilterBuilders.rangeFilter("Experiance").from(smonth).to(emonth));
FilteredQueryBuilder fqb = new FilteredQueryBuilder(qb, fb);

Finding product in category

I need to find products in different categories on eBay. But when I use the tutorial code
ebay.apis.eblbasecomponents.FindProductsRequestType request = new ebay.apis.eblbasecomponents.FindProductsRequestType();
request.setCategoryID("Art");
request.setQueryKeywords("furniture");
I get the following error: QueryKeywords, CategoryID and ProductID cannot be used together.
So how is this done?
EDIT: the tutorial code is here.
EDIT2: the link to the tutorial code died, apparently. I've continued to search and the category cannot be used with the keyword search, but there's a Domain that you could presumably add to the request, but sadly it's not in the API - so I'm not sure if indeed it can be done.
The less-than-great eBay API doc is here.
This is my full request:
Shopping service = new ebay.apis.eblbasecomponents.Shopping();
ShoppingInterface port = service.getShopping();
bp = (BindingProvider) port;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
// Add the logging handler
List<Handler> handlerList = bp.getBinding().getHandlerChain();
if (handlerList == null) {
handlerList = new ArrayList<Handler>();
}
LoggingHandler loggingHandler = new LoggingHandler();
handlerList.add(loggingHandler);
bp.getBinding().setHandlerChain(handlerList);
Map<String,Object> requestProperties = bp.getRequestContext();
Map<String, List<String>> httpHeaders = new HashMap<String, List<String>>();
requestProperties.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
httpHeaders.put("X-EBAY-API-CALL-NAME", Collections.singletonList(CALLNAME));
httpHeaders.put("X-EBAY-API-APP-ID", Collections.singletonList(APPID));
httpHeaders.put("X-EBAY-API-VERSION", Collections.singletonList(VERSION));
requestProperties.put(MessageContext.HTTP_REQUEST_HEADERS, httpHeaders);
// initialize WS operation arguments here
FindProductsRequestType request = new FindProductsRequestType();
request.setAvailableItemsOnly(true);
request.setHideDuplicateItems(true);
request.setMaxEntries(2);
request.setPageNumber(1);
request.setQueryKeywords("Postcard");
request.setDomain("");
The last line, which should set the domain like I need to, does not compile. Any idea how to solve this?
EDIT 3: I gave up on the Java API and I'm doing direct REST. The categories on eBay are actually domains now, and the URL looks like this:
String findProducts = "http://open.api.ebay.com/shopping?callname=FindProducts&responseencoding=XML&appid=" + APPID
+ "&siteid=0&version=525&"
+ "&AvailableItemsOnly=true"
+ "&QueryKeywords=" + keywords
+ "&MaxEntries=10"
+ "&DomainName=" + domainName;
This works, but you want to hear a joke? It seems like not all the domains are listed here and so it doesn't really solve this problem. Pretty disappointing work by eBay.
The solution for finding items based on keywords, in a category, is to use findItemsAdvanced. Could have saved me a lot of time if the docs for FindProducts stated this, instead of just saying that you can use either keyword search OR category search.
This is the API URL:
http://open.api.ebay.com/shoppingcallname=findItemsAdvanced&responseencoding=XML&appid=" + APPID
+ "&siteid=0&version=525&"
+ "&AvailableItemsOnly=true"
+ "&QueryKeywords=" + keywords
+ "&categoryId=" + categoryId
+ "&MaxEntries=50
For completion, if you want to get a list of all the top categories you can use this:
http://open.api.ebay.com/Shopping?callname=GetCategoryInfo&appid=" + APPID + "&siteid=0&CategoryID=-1&version=729&IncludeSelector=ChildCategories

Obtain a share UpdateKey from LinkedIn using LinkedIn J and getNetworkUpdates() with Coldfusion

Using the "Network Updates API" example at the following link I am able to post network updates with no problem using client.postNetworkUpdate(updateText).
http://code.google.com/p/linkedin-j/wiki/GettingStarted
So posting works great.. However posting an update does not return an "UpdateKey" which is used to retrieve stats for post itself such as comments, likes, etc. Without the UpdateKey I cannot retrieve stats. So what I would like to do is post, then retrieve the last post using the getNetworkUpdates() function, and in that retrieval will be the UpdateKey that I need to use later to retrieve stats. Here's a sample script in Java on how to get network updates, but I need to do this in Coldfusion instead of Java.
Network network = client.getNetworkUpdates(EnumSet.of(NetworkUpdateType.STATUS_UPDATE));
System.out.println("Total updates fetched:" + network.getUpdates().getTotal());
for (Update update : network.getUpdates().getUpdateList()) {
System.out.println("-------------------------------");
System.out.println(update.getUpdateKey() + ":" + update.getUpdateContent().getPerson().getFirstName() + " " + update.getUpdateContent().getPerson().getLastName() + "->" + update.getUpdateContent().getPerson().getCurrentStatus());
if (update.getUpdateComments() != null) {
System.out.println("Total comments fetched:" + update.getUpdateComments().getTotal());
for (UpdateComment comment : update.getUpdateComments().getUpdateCommentList()) {
System.out.println(comment.getPerson().getFirstName() + " " + comment.getPerson().getLastName() + "->" + comment.getComment());
}
}
}
Anyone have any thoughts on how to accomplish this using Coldfusion?
Thanks
I have not used that api, but I am guessing you could use the first two lines to grab the number of updates. Then use the overloaded client.getNetworkUpdates(start, end) method to retrieve the last update and obtain its key.
Totally untested, but something along these lines:
<cfscript>
...
// not sure about accessing the STATUS_UPDATE enum. One of these should work:
// method 1
STATUS_UPDATE = createObject("java", "com.google.code.linkedinapi.client.enumeration.NetworkUpdateType$STATUS_UPDATE");
// method 2
NetworkUpdateType = createObject("java", "com.google.code.linkedinapi.client.enumeration.NetworkUpdateType");
STATUS_UPDATE = NetworkUpdateType.valueOf("STATUS_UPDATE");
enumSet = createObject("java", "java.util.EnumSet");
network = yourClientObject.getNetworkUpdates(enumSet.of(STATUS_UPDATE));
numOfUpdates = network.getUpdates().getTotal();
// Add error handling in case numOfUpdates = 0
result = yourClientObject.getNetworkUpdates(numOfUpdates, numOfUpdates);
lastUpdate = result.getUpdates().getUpdateList().get(0);
key = lastUpdate.getUpdateKey();
</cfscript>
You can also use socialauth library to retrieve updates and post status on linkedin.
http://code.google.com/p/socialauth

Jira Key Performance Indicator Chart Gadget

I need to create a chart that shows Key Performance Indicator.
(total of issues / issues resolved)
I'm using this query to return count of total issues and unresolved issues:
JqlQueryBuilder.newBuilder();
final JqlClauseBuilder jqlClauseBuilder = JqlQueryBuilder.newBuilder().where().defaultAnd().unresolved();
Query query;
Query unresolvedQuery;
query = jqlClauseBuilder.created().gtEq("-" + Integer.toString(start) + "d").and().
created().ltEq("-" + Integer.toString(start-delta) + "d").buildQuery();
unresolvedQuery = jqlClauseBuilder.created().gtEq("-" + Integer.toString(start) + "d").and().
created().ltEq("-" + Integer.toString(start-delta) + "d").
unresolved().buildQuery();
Long totIssues = searchService.searchCount(authenticationContext.getUser(), query);
Long solvedIssues = totIssues - searchService.searchCount(authenticationContext.getUser(), unresolvedQuery);
The problem is that I get a null value...
What's wrong?
I found out why.
The query is correct but the problem was that query=... is in a FOR so I had to move also the declaration of jqlClauseBuilder, otherwise after the first query, all the others are all wrong created.

Categories

Resources