I have a CosmosDB container with 10000 documents. Every document contains a random (geography) Point that is within a specific bounds.
I am using the CosmosDB emulator and Azure Cosmos DB .NET SDK (v3) to perform some geo-spatial queries. however, queries using ST_INTERSECTS and ST_WITHIN are giving different results than a query using latitude and longitude min/max values, as illustrated below:
1 - Query using explicit latitude / longitude minimum and maximum values - gives the correct result:
SELECT r.id FROM testcontainer r
WHERE r.lat >= 53.393183 AND r.lat <= 53.657421
AND r.lon >= -113.733431 AND r.lon <= -113.247049
Query Total time: 00:00:00.1293465
Total Request Units consumed: 244.15
Documents found: 10000
2 - Query using ST_INTERSECTS - should have the same result as query #1?
SELECT r.id FROM testcontainer r
WHERE ST_INTERSECTS( r.geopoint, {'type':'Polygon','coordinates':[[[-113.247049,53.657421],[-113.733431,53.657421],[-113.733431,53.393183],[-113.247049,53.393183],[-113.247049,53.657421]]]})
Query Total time: 00:00:00.3134729
Total Request Units consumed: 226.17000000000002
Documents found: 9994
3 - Query using ST_WITHIN - should have the same result as query #1?
SELECT r.id FROM testcontainer r
WHERE ST_WITHIN( r.geopoint, {'type':'Polygon','coordinates':[[[-113.247049,53.657421],[-113.733431,53.657421],[-113.733431,53.393183],[-113.247049,53.393183],[-113.247049,53.657421]]]})
Query Total time: 00:00:00.3107136
Total Request Units consumed: 962.91
Documents found: 9994
All of the queries above should have returned 10000 documents -- but the ST_INTERSECTS and ST_WITHIN seem to fall short and only query #1 gives the correct result - I cannot explain why.
Does anyone have any insights as to why ST_WITHIN and ST_INTERSECTS would not give the same result as the query with explicit latitude / longitude values?
Additional Information:
When I do the following query:
SELECT r.id, r.geopoint FROM testcontainer r
WHERE NOT ST_INTERSECTS( r.geopoint, {'type':'Polygon','coordinates':[[[-113.247049,53.657421],[-113.733431,53.657421],[-113.733431,53.393183],[-113.247049,53.393183],[-113.247049,53.657421]]]})
The query result is the missing 6 documents - but looking at the results, there is only one result with a longitude value of -113.247049 that matches a longitude value specified in the bounds.
[
{
"id": "6892de3d-4b8a-42c6-8421-18b65a70146f",
"geopoint": {
"type": "Point",
"coordinates": [
-113.465305,
53.393386
]
}
},
{
"id": "6b89e0fc-7f65-4f75-90db-63dc599b98dd",
"geopoint": {
"type": "Point",
"coordinates": [
-113.247049,
53.623584
]
}
},
{
"id": "467a388a-f0fd-4717-9eb5-3a8f538df38b",
"geopoint": {
"type": "Point",
"coordinates": [
-113.302698,
53.393212
]
}
},
{
"id": "ada61462-5131-4e25-b0be-3bee42fcde05",
"geopoint": {
"type": "Point",
"coordinates": [
-113.362105,
53.393276
]
}
},
{
"id": "3bfd30a7-abcd-4216-905f-5a3831869626",
"geopoint": {
"type": "Point",
"coordinates": [
-113.340676,
53.393227
]
}
},
{
"id": "c259a408-e6f0-4050-b7ad-6f55d9a614da",
"geopoint": {
"type": "Point",
"coordinates": [
-113.400457,
53.393275
]
}
}
]
Below is an Excel (screen snapshot) that shows the delta (difference) between the bounds lat/lon values and those from the "missing" documents:
Looking at the differences, a small deviation will exclude some points when using ST_WITHIN / ST_INTERSECTS as per the answer given by Michael Entin.
Thanks.
That's the difference between geography (shapes on a sphere with geodesic edges) and geometry (shapes on a flat map with edges that look straight on that map).
If you work with geography, the "horizonal" edges of your GeoJson "rectangle" follow geodesics and thus bend a bit towards poles. Thus the rectangle describes a slightly different shape from what you expect.
If the min/max results in your first query are what you want - switch to geometry.
I am trying to graph the construction of Thompson using graphviz, and I would like to know if anyone could help me graph one of the rules so that I can do the others.
I attach a reference image: https://en.wikipedia.org/wiki/Thompson%27s_construction#/media/File:Thompson-kleene-star.svg
digraph finite_state_machine {
rankdir=LR;
size="8,5"
node [shape = doublecircle]; s3;
node [shape = circle];
s0 -> s1 [ label = "ε" ];
s0 -> s3 [ label = "ε" ];
s1 -> s2 [ label = "ε" ];
s2 -> s1 [ label = "ε" ];
s2 -> s3 [ label = "ε" ];
}
Graphviz programs try to avoid placing nodes on top of other nodes. You can get the node placement by explicitly providing pos attributes for all the nodes. (Not that difficult, but a nuisance.) You can get neato to generate all straight edges, but you will have to provide the (spline) coordinates for all the arcs. Otherwise you get this:
As an alternative, instead of graphviz, if you use dpic or gpic, this program:
.PS
.defcolor pink rgb #FFC0CB
circlerad=circlerad*.8
## we need to place the large oval before we place nodes on it
Qx: circle invis ; line invis; circle invis; A: line invis;
ellipseht=ellipseht*2;
ellipsewid=ellipsewid*2
E:ellipse at A.c shaded "pink" " N(s)"
move to Qx.w
Q: circle "q" ; arrow "ε" ""; C1: circle ; A: line invis; C2: circle ; arrow "ε" ""; F: circle "f";
circlerad=circlerad*.8
F1:circle at last circle
move to E.n; up; P1: box invis "ε"
arc -> from C2.n to C1.n
arcrad=2
arc -> from Q.s to F.s
### gpic version of greek chars:
# move to E.s; down; box invis "" "\[*e]"
########################################
### dpic/svg version of greek chars
move to E.s; down; box invis "" "ε"
.PE
produced this:
gpic is part of the GNU (Linux) groff package.
dpic can be found here: https://ece.uwaterloo.ca/~aplevich/dpic/
I want to render a directed graph like:
A
^ ^
/ \
/ \
B C
But no matter what order I put the statements in, dot insists on generating an image that looks like:
B C
\ /
\ /
v v
A
I've tried specifying the port, but then the edges just wrap around. It doesn't change the position of the nodes.
The solution is rankdir
digraph G {
rankdir="BT"
B->A
C->A
}
rankdir is the solution if you want to build your whole graph from bottom to top. A more flexible approach is to just tell the edges to point backward:
digraph G
{
A -> B[ dir = back ];
A -> C[ dir = back ];
}
yields
You could also write
A -> { B C }[ dir = back ];
Or you could give the general instructions for all edges defined after this instruction to point backward:
edge[ dir = back ];
This can be undone by
edge[ dir = forw ];
Hence,
digraph G
{
edge[ dir = back ];
A -> B;
A -> C;
edge[ dir = forw ];
{ B C } -> D;
}
yields
Consider following nodes that are connected between each other with 2 type of edges: direct and intersect. The query needs to discover all possible paths between 2 nodes that satisfies all following rules:
0..N direct edges
0..1 intersect edge
intersect edge can be between direct edges
These paths are considered valid between nodeA and nodeZ:
(nodeA)-[:direct]->(nodeB)-[:direct]->(nodeC)->[:direct]->(nodeZ)
(nodeA)-[:intersect]->(nodeB)-[:direct]->(nodeC)->[:direct]->(nodeZ)
(nodeA)-[:direct]->(nodeB)-[:intersect]->(nodeC)->[:direct]->(nodeZ)
(nodeA)-[:direct]->(nodeB)->[:direct]->(nodeC)-[:intersect]->(nodeZ)
Basically intersect edge can happen anywhere in the path but only once.
My ideal cypher query in non-existing neo4j version would be this:
MATCH (from)-[:direct*0..N|:intersect*0..1]->(to)
But neo4j doesn't support multiple constraints for edges type :(.
UPDATE 23.04.16
There 6609 nodes (out of 550k total), 5184 edges of type direct (out of 440k total) and 34119 of type intersect (out of 37289 total). There are some circular references expected (which neo4j avoids, isn't it?)
The query that looked promising but failed to finish in a manner of seconds:
MATCH p = (from {from: 1})-[:direct|intersect*0..]->(to {to: 99})
WHERE
123 < from.departureTS < 123 + 86400 //next day
AND REDUCE(s = 0, x IN RELATIONSHIPS(p) | CASE TYPE(x) WHEN 'intersect' THEN s + 1 ELSE s END) <= 1
return p;
Here is a query that conforms to the stated requirements:
MATCH p = (from)-[:direct|intersect*0..]->(to)
WHERE REDUCE(s = 0, x IN RELATIONSHIPS(p) |
CASE WHEN TYPE(x) = 'intersect' THEN s + 1 ELSE s END) <= 1
return p;
It returns all paths with 0 or more direct relationships and 0 or 1 intersect relationships.
This will do what you want:
// Cybersam's correction:
MATCH p = ((from)-[:direct*0..]->(middle)-[:intersect*0..1]->(middle2)-[:direct*0..]->(to)) return DISTINCT p;
return p
Here's the test scenario I used:
create (a:nodeA {name: "A"})
create (b:nodeB {name: "B"})
create (c:nodeC {name: "C"})
create (z:nodeZ {name: "Z"})
merge (a)-[:direct {name: "D11"}]->(b)-[:direct {name: "D21"}]->(c)-[:direct {name: "D31"}]->(z)
merge (a)-[:intersect {name: "I12"}]->(b)-[:direct {name: "D22"}]->(c)-[:direct {name: "D32"}]->(z)
merge (a)-[:direct {name: "D13"}]->(b)-[:intersect {name: "I23"}]->(c)-[:direct {name: "D33"}]->(z)
merge (a)-[:direct {name: "D14"}]->(b)-[:direct {name: "D24"}]->(c)-[:intersect {name: "I34"}]->(z)
merge (a)-[:intersect {name: "I15"}]->(z)
// Cybersam's correction:
MATCH p = ((from)-[:direct*0..]->(middle)-[:intersect*0..1]->(middle2)-[:direct*0..]->(to)) return DISTINCT p;
return p
I made the mistake of thinking the graph on the browser reflected the data that was returned in "p" - it did not, you have to look at the "rows" part of the report to get all the details.
This query will also return single nodes- which fits the requirements.
Part of what I am trying to do is make a breed of turtles move around, but when one reaches its destination that turtle waits for a certain number of ticks before continuing ? Also is it possible to make turtles wait for different number of ticks depending upon their destination ( different patch colors). Is it a case of making a turtle breed or global variable to count the number of ticks? The hopefully relevant code is below.
You are right, this can be done by making the turtles count the number of ticks they have been on a patch. Also this has to be a turtle variable and not a global variable since each turtle will have a different value for this
The approach, I have used is this:
Once the turtle arrives at its destination record the ticks (the global variable which records the number of ticks that have passed till now) into a turtle variable say ticks-since-here. This works like a time-stamp.
On each successive tick check the difference between the current-time ticks global variable and the ticks-since-here turtle variable. If this becomes greater than the number of ticks the turtle is allowed to stay on the patch, let it choose and move to the new destination.
breed [visitors visitor]
globals [ number-of-visitors ]
visitors-own [
; visitors own destination
destination
ticks-since-here
]
to go
ask visitors [
move
]
tick
end
to move
; Instructions to move the agents around the environment go here
; comparing patch standing on to dest, if at dest then choose random new dest
; then more forward towards new dest
ifelse ( patch-here = destination )
[
if ticks - ticks-since-here > ticks-to-stay-on-patch patch-here
[
set ticks-since-here 0
set destination one-of patches with
[
pcolor = 65 or pcolor = 95 or pcolor = 125 or pcolor = 25 or pcolor = 15 or pcolor = 5
]
]
]
[
face destination
forward 1
if ( patch-here = destination )
[
set ticks-since-here ticks
]
]
end
to-report ticks-to-stay-on-patch [p]
if [pcolor] of p = 65
[
report 6
]
if [pcolor] of p = 95
[
report 5
]
if [pcolor] of p = 125
[
report 4
]
if [pcolor] of p = 25
[
report 3
]
if [pcolor] of p = 15
[
report 2
]
if [pcolor] of p = 5
[
report 1
]
end
to setup-people
;;;; added the following lines to facilitate world view creation
ask patches
[
set pcolor one-of [65 95 125 25 15 5]
]
set number-of-visitors 100
;;;;
create-visitors number-of-visitors
[
ask visitors
[
; set the shape of the visitor to "visitor"
set shape "person"
; set the color of visitor to white
set color white
; give person a random xy
setxy (random 50) (random 50)
; set visitors destination variable
set destination one-of patches with
[
pcolor = 65 or pcolor = 95 or pcolor = 125 or pcolor = 25 or pcolor = 15 or pcolor = 5
]
]
]
end