Skip to content

Commit a1ac6ba

Browse files
committed
MLE-14438 : Use shortest-path function in Java plan builder
1 parent 0c5e2e5 commit a1ac6ba

File tree

5 files changed

+320
-24
lines changed

5 files changed

+320
-24
lines changed

marklogic-client-api-functionaltests/src/test/java/com/marklogic/client/fastfunctest/AbstractFunctionalTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public abstract class AbstractFunctionalTest extends BasicJavaClientREST {
4646
protected static MarkLogicVersion markLogicVersion;
4747

4848
protected static boolean isML11OrHigher;
49+
protected static boolean isML12OrHigher;
4950
private static String originalHttpPort;
5051
private static String originalRestServerName;
5152

@@ -63,6 +64,7 @@ public static void initializeClients() {
6364
markLogicVersion = MarkLogicVersion.getMarkLogicVersion(connectAsAdmin());
6465
System.out.println("ML version: " + markLogicVersion.getVersionString());
6566
isML11OrHigher = markLogicVersion.getMajor() >= 11;
67+
isML12OrHigher = markLogicVersion.getMajor() >= 12;
6668

6769
client = newDatabaseClientBuilder().build();
6870
schemasClient = newDatabaseClientBuilder().withDatabase("java-functest-schemas").build();

marklogic-client-api-functionaltests/src/test/java/com/marklogic/client/fastfunctest/TestOpticOnTriples.java

+132
Original file line numberDiff line numberDiff line change
@@ -1423,4 +1423,136 @@ public void testPatternValuePermutations()
14231423
assertEquals( "19", nodeValNeg1.path("PlayerAge").path("value").asText());
14241424
assertEquals( "Midfielder", nodeValNeg1.path("PlayerPosition").path("value").asText());
14251425
}
1426+
1427+
@Test
1428+
public void testShortestPathWithColumnInputs()
1429+
{
1430+
if(!isML12OrHigher){
1431+
return;
1432+
}
1433+
1434+
RowManager rowMgr = client.newRowManager();
1435+
PlanBuilder p = rowMgr.newPlanBuilder();
1436+
1437+
PlanColumn teamIdCol = p.col("player_team");
1438+
PlanColumn teamNameCol = p.col("team_name");
1439+
PlanColumn teamCityCol = p.col("team_city");
1440+
1441+
PlanPrefixer team = p.prefixer("http://marklogic.com/mlb/team/");
1442+
PlanBuilder.ModifyPlan team_plan = p.fromTriples(
1443+
p.pattern(teamIdCol, team.iri("name"), teamNameCol),
1444+
p.pattern(teamIdCol, team.iri("city"), teamCityCol)
1445+
).shortestPath(p.col("team_name"), p.col("team_city"), p.col("path"), p.col("length"));
1446+
JacksonHandle jacksonHandle = new JacksonHandle().withMimetype("application/json");
1447+
rowMgr.resultDoc(team_plan, jacksonHandle);
1448+
JsonNode jsonResults = jacksonHandle.get();
1449+
JsonNode jsonBindingsNodes = jsonResults.path("rows");
1450+
for (int i=0; i<jsonBindingsNodes.size(); i++){
1451+
JsonNode path = jsonBindingsNodes.path(i);
1452+
assertNotNull(path.path("team_name"));
1453+
assertNotNull(path.path("team_city"));
1454+
assertNotNull(path.path("path"));
1455+
assertEquals("1",path.path("length").path("value").toString());
1456+
}
1457+
}
1458+
1459+
@Test
1460+
public void testShortestPathWithStringInputs()
1461+
{
1462+
if(!isML12OrHigher){
1463+
return;
1464+
}
1465+
1466+
RowManager rowMgr = client.newRowManager();
1467+
PlanBuilder p = rowMgr.newPlanBuilder();
1468+
1469+
PlanColumn teamIdCol = p.col("player_team");
1470+
PlanColumn teamNameCol = p.col("team_name");
1471+
PlanColumn teamCityCol = p.col("team_city");
1472+
1473+
PlanPrefixer team = p.prefixer("http://marklogic.com/mlb/team/");
1474+
PlanBuilder.ModifyPlan team_plan = p.fromTriples(
1475+
p.pattern(teamIdCol, team.iri("name"), teamNameCol),
1476+
p.pattern(teamIdCol, team.iri("city"), teamCityCol)
1477+
).shortestPath("team_name", "team_city", "path", "length");
1478+
JacksonHandle jacksonHandle = new JacksonHandle().withMimetype("application/json");
1479+
rowMgr.resultDoc(team_plan, jacksonHandle);
1480+
JsonNode jsonResults = jacksonHandle.get();
1481+
JsonNode jsonBindingsNodes = jsonResults.path("rows");
1482+
for (int i=0; i<jsonBindingsNodes.size(); i++){
1483+
JsonNode path = jsonBindingsNodes.path(i);
1484+
assertNotNull(path.path("team_name"));
1485+
assertNotNull(path.path("team_city"));
1486+
assertNotNull(path.path("path"));
1487+
assertEquals("1",path.path("length").path("value").toString());
1488+
}
1489+
}
1490+
1491+
// TODO: Enable testShortestPathWithWeight and testShortestPathWithWeightColumn tests after server code starts
1492+
// accepting weight column and string.
1493+
@Disabled
1494+
@Test
1495+
public void testShortestPathWithWeight()
1496+
{
1497+
if(!isML12OrHigher){
1498+
return;
1499+
}
1500+
1501+
RowManager rowMgr = client.newRowManager();
1502+
PlanBuilder p = rowMgr.newPlanBuilder();
1503+
1504+
PlanColumn teamIdCol = p.col("player_team");
1505+
PlanColumn teamNameCol = p.col("team_name");
1506+
PlanColumn teamCityCol = p.col("team_city");
1507+
1508+
PlanPrefixer team = p.prefixer("http://marklogic.com/mlb/team/");
1509+
PlanBuilder.ModifyPlan team_plan = p.fromTriples(
1510+
p.pattern(teamIdCol, team.iri("name"), teamNameCol),
1511+
p.pattern(teamIdCol, team.iri("city"), teamCityCol)
1512+
).shortestPath("team_name", "team_city", "path", "length", "weight");
1513+
JacksonHandle jacksonHandle = new JacksonHandle().withMimetype("application/json");
1514+
rowMgr.resultDoc(team_plan, jacksonHandle);
1515+
JsonNode jsonResults = jacksonHandle.get();
1516+
JsonNode jsonBindingsNodes = jsonResults.path("rows");
1517+
for (int i=0; i<jsonBindingsNodes.size(); i++){
1518+
JsonNode path = jsonBindingsNodes.path(i);
1519+
assertNotNull(path.path("team_name"));
1520+
assertNotNull(path.path("team_city"));
1521+
assertNotNull(path.path("path"));
1522+
assertEquals("1",path.path("length").path("value").toString());
1523+
}
1524+
}
1525+
1526+
@Disabled
1527+
@Test
1528+
public void testShortestPathWithWeightColumn()
1529+
{
1530+
if(!isML12OrHigher){
1531+
return;
1532+
}
1533+
1534+
RowManager rowMgr = client.newRowManager();
1535+
PlanBuilder p = rowMgr.newPlanBuilder();
1536+
1537+
PlanColumn teamIdCol = p.col("player_team");
1538+
PlanColumn teamNameCol = p.col("team_name");
1539+
PlanColumn teamCityCol = p.col("team_city");
1540+
1541+
PlanPrefixer team = p.prefixer("http://marklogic.com/mlb/team/");
1542+
PlanBuilder.ModifyPlan team_plan = p.fromTriples(
1543+
p.pattern(teamIdCol, team.iri("name"), teamNameCol),
1544+
p.pattern(teamIdCol, team.iri("city"), teamCityCol)
1545+
).shortestPath(p.col("team_name"), p.col("team_city"), p.col("path"), p.col("length"), p.col("weight"));
1546+
JacksonHandle jacksonHandle = new JacksonHandle().withMimetype("application/json");
1547+
rowMgr.resultDoc(team_plan, jacksonHandle);
1548+
JsonNode jsonResults = jacksonHandle.get();
1549+
JsonNode jsonBindingsNodes = jsonResults.path("rows");
1550+
for (int i=0; i<jsonBindingsNodes.size(); i++){
1551+
JsonNode path = jsonBindingsNodes.path(i);
1552+
assertNotNull(path.path("team_name"));
1553+
assertNotNull(path.path("team_city"));
1554+
assertNotNull(path.path("path"));
1555+
assertEquals("1",path.path("length").path("value").toString());
1556+
}
1557+
}
14261558
}

marklogic-client-api/src/main/java/com/marklogic/client/expression/PlanBuilder.java

+77
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,7 @@ protected PlanBuilder(
13801380
* Provides a client interface to the <a href="http://docs.marklogic.com/op:xml-attribute-seq" target="mlserverdoc">op:xml-attribute-seq</a> server function.
13811381
* @param attribute the attribute values for the sequence
13821382
* @return a server expression with the <a href="{@docRoot}/doc-files/types/attribute-node.html">attribute-node</a> server data type
1383+
* @deprecated (as of 4.2) construct a {@link com.marklogic.client.type.ServerExpression} sequence with <a href="PlanBuilderBase.html#ml-server-expression-sequence">PlanBuilder.seq()</a>
13831384
*/
13841385
public abstract ServerExpression xmlAttributeSeq(ServerExpression... attribute);
13851386
/**
@@ -1960,6 +1961,82 @@ public interface ModifyPlan extends PreparePlan, PlanBuilderBase.ModifyPlanBase
19601961
* @return a ModifyPlan object
19611962
*/
19621963
public abstract ModifyPlan unnestLeftOuter(PlanExprCol inputColumn, PlanExprCol valueColumn, PlanExprCol ordinalColumn);
1964+
/**
1965+
* This method can be used to find the shortest path between two nodes in a given graph.
1966+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1967+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1968+
* @return a ModifyPlan object
1969+
* @since 7.1.0; requires MarkLogic 12
1970+
*/
1971+
public abstract ModifyPlan shortestPath(String start, String end);
1972+
/**
1973+
* This method can be used to find the shortest path between two nodes in a given graph.
1974+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1975+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1976+
* @return a ModifyPlan object
1977+
* @since 7.1.0; requires MarkLogic 12
1978+
*/
1979+
public abstract ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end);
1980+
/**
1981+
* This method can be used to find the shortest path between two nodes in a given graph.
1982+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1983+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1984+
* @param path The column is the output column representing the actual shortest path(s) taken from start to end. Values are not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1985+
* @return a ModifyPlan object
1986+
* @since 7.1.0; requires MarkLogic 12
1987+
*/
1988+
public abstract ModifyPlan shortestPath(String start, String end, String path);
1989+
/**
1990+
* This method can be used to find the shortest path between two nodes in a given graph.
1991+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1992+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1993+
* @param path The column is the output column representing the actual shortest path(s) taken from start to end. Values are not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
1994+
* @return a ModifyPlan object
1995+
* @since 7.1.0; requires MarkLogic 12
1996+
*/
1997+
public abstract ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path);
1998+
/**
1999+
* This method can be used to find the shortest path between two nodes in a given graph.
2000+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2001+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2002+
* @param path The column is the output column representing the actual shortest path(s) taken from start to end. Values are not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2003+
* @param length The column is the output column representing the length of the shortest path. Value is not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2004+
* @return a ModifyPlan object
2005+
* @since 7.1.0; requires MarkLogic 12
2006+
*/
2007+
public abstract ModifyPlan shortestPath(String start, String end, String path, String length);
2008+
/**
2009+
* This method can be used to find the shortest path between two nodes in a given graph.
2010+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2011+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2012+
* @param path The column is the output column representing the actual shortest path(s) taken from start to end. Values are not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2013+
* @param length The column is the output column representing the length of the shortest path. Value is not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2014+
* @return a ModifyPlan object
2015+
* @since 7.1.0; requires MarkLogic 12
2016+
*/
2017+
public abstract ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path, PlanExprCol length);
2018+
/**
2019+
* This method can be used to find the shortest path between two nodes in a given graph.
2020+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2021+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2022+
* @param path The column is the output column representing the actual shortest path(s) taken from start to end. Values are not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2023+
* @param length The column is the output column representing the length of the shortest path. Value is not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2024+
* @param weight the weight value. See {@link PlanBuilder#col(XsStringVal)}
2025+
* @return a ModifyPlan object
2026+
* @since 7.1.0; requires MarkLogic 12
2027+
*/
2028+
public abstract ModifyPlan shortestPath(String start, String end, String path, String length, String weight);
2029+
/**
2030+
* This method can be used to find the shortest path between two nodes in a given graph.
2031+
* @param start The column representing the input starting subject of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2032+
* @param end The column representing the input ending object of the shortest path search. The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2033+
* @param path The column is the output column representing the actual shortest path(s) taken from start to end. Values are not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2034+
* @param length The column is the output column representing the length of the shortest path. Value is not returned for this column if this is the empty sequence.The columns can be named with a string or a column parameter function such as op:col. See {@link PlanBuilder#col(XsStringVal)}
2035+
* @param weight the weight value. See {@link PlanBuilder#col(XsStringVal)}
2036+
* @return a ModifyPlan object
2037+
* @since 7.1.0; requires MarkLogic 12
2038+
*/
2039+
public abstract ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path, PlanExprCol length, PlanExprCol weight);
19632040
}
19642041

19652042

marklogic-client-api/src/main/java/com/marklogic/client/impl/PlanBuilderImpl.java

+72
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,78 @@ public ModifyPlan select(PlanExprColSeq columns, XsStringVal qualifierName) {
22062206
}
22072207

22082208

2209+
@Override
2210+
public ModifyPlan shortestPath(String start, String end) {
2211+
return shortestPath((start == null) ? (PlanExprCol) null : exprCol(start), (end == null) ? (PlanExprCol) null : exprCol(end));
2212+
}
2213+
2214+
2215+
@Override
2216+
public ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end) {
2217+
if (start == null) {
2218+
throw new IllegalArgumentException("start parameter for shortestPath() cannot be null");
2219+
}
2220+
if (end == null) {
2221+
throw new IllegalArgumentException("end parameter for shortestPath() cannot be null");
2222+
}
2223+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "shortest-path", new Object[]{ start, end });
2224+
}
2225+
2226+
2227+
@Override
2228+
public ModifyPlan shortestPath(String start, String end, String path) {
2229+
return shortestPath((start == null) ? (PlanExprCol) null : exprCol(start), (end == null) ? (PlanExprCol) null : exprCol(end), (path == null) ? (PlanExprCol) null : exprCol(path));
2230+
}
2231+
2232+
2233+
@Override
2234+
public ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path) {
2235+
if (start == null) {
2236+
throw new IllegalArgumentException("start parameter for shortestPath() cannot be null");
2237+
}
2238+
if (end == null) {
2239+
throw new IllegalArgumentException("end parameter for shortestPath() cannot be null");
2240+
}
2241+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "shortest-path", new Object[]{ start, end, path });
2242+
}
2243+
2244+
2245+
@Override
2246+
public ModifyPlan shortestPath(String start, String end, String path, String length) {
2247+
return shortestPath((start == null) ? (PlanExprCol) null : exprCol(start), (end == null) ? (PlanExprCol) null : exprCol(end), (path == null) ? (PlanExprCol) null : exprCol(path), (length == null) ? (PlanExprCol) null : exprCol(length));
2248+
}
2249+
2250+
2251+
@Override
2252+
public ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path, PlanExprCol length) {
2253+
if (start == null) {
2254+
throw new IllegalArgumentException("start parameter for shortestPath() cannot be null");
2255+
}
2256+
if (end == null) {
2257+
throw new IllegalArgumentException("end parameter for shortestPath() cannot be null");
2258+
}
2259+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "shortest-path", new Object[]{ start, end, path, length });
2260+
}
2261+
2262+
2263+
@Override
2264+
public ModifyPlan shortestPath(String start, String end, String path, String length, String weight) {
2265+
return shortestPath((start == null) ? (PlanExprCol) null : exprCol(start), (end == null) ? (PlanExprCol) null : exprCol(end), (path == null) ? (PlanExprCol) null : exprCol(path), (length == null) ? (PlanExprCol) null : exprCol(length), (weight == null) ? (PlanExprCol) null : exprCol(weight));
2266+
}
2267+
2268+
2269+
@Override
2270+
public ModifyPlan shortestPath(PlanExprCol start, PlanExprCol end, PlanExprCol path, PlanExprCol length, PlanExprCol weight) {
2271+
if (start == null) {
2272+
throw new IllegalArgumentException("start parameter for shortestPath() cannot be null");
2273+
}
2274+
if (end == null) {
2275+
throw new IllegalArgumentException("end parameter for shortestPath() cannot be null");
2276+
}
2277+
return new PlanBuilderSubImpl.ModifyPlanSubImpl(this, "op", "shortest-path", new Object[]{ start, end, path, length, weight });
2278+
}
2279+
2280+
22092281
@Override
22102282
public ModifyPlan union(ModifyPlan right) {
22112283
if (right == null) {

0 commit comments

Comments
 (0)