Одной из вещей, которую я хотел добавить к своему футбольному графику, было что-то, связанное с местоположением, так что я мог попробовать neo4j пространственный, и я подумал, что самый простой способ сделать это — смоделировать местоположение футбольных стадионов.
Для начала мне нужно было добавить пространственное как неуправляемое расширение к моей папке плагинов neo4j, что включало в себя следующее:
$ git clone git://github.com/neo4j/spatial.git spatial $ cd spatial $ mvn clean package -Dmaven.test.skip=true install $ unzip target/neo4j-spatial-0.11-SNAPSHOT-server-plugin.zip -d /path/to/neo4j-community-1.9.M04/plugins/ $ /path/to/neo4j-community-1.9.M04/plugins/ restart
Если он установлен правильно, то вы должны увидеть такой вывод при вводе ‘curl’ для веб-интерфейса:
$ curl -L http://localhost:7474/db/data { "extensions" : { ... "SpatialPlugin" : { "addEditableLayer" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addEditableLayer", "addCQLDynamicLayer" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addCQLDynamicLayer", "findGeometriesWithinDistance" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/findGeometriesWithinDistance", "updateGeometryFromWKT" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/updateGeometryFromWKT", "addGeometryWKTToLayer" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addGeometryWKTToLayer", "getLayer" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/getLayer", "addSimplePointLayer" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addSimplePointLayer", "findGeometriesInBBox" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/findGeometriesInBBox", "addNodeToLayer" : "http://localhost:7474/db/data/ext/SpatialPlugin/graphdb/addNodeToLayer" }, … }, ... "neo4j_version" : "1.9.M04"
Следующим шагом было создание пространственного индекса, содержащего широты / долготы стадионов.
В IndexProviderTest есть хороший пример, который я смог адаптировать, чтобы делать то, что я хотел.
Я получил список стадионов вместе с их местоположением в виде CSV из блога Криса Белла .
Вывод выглядит так:
Name,Team,Capacity,Latitude,Longitude "Adams Park","Wycombe Wanderers",10284,51.6306,-0.800299 "Almondvale Stadium","Livingston",10122,55.8864,-3.52207 "Amex Stadium","Brighton and Hove Albion",22374,50.8609,-0.08014 "Anfield","Liverpool",45522,53.4308,-2.96096 "Ashton Gate","Bristol City",21497,51.44,-2.62021 "B2net Stadium","Chesterfield",10400,53.2535,-1.4272
Я получил следующий код для создания узлов для каждого стадиона и добавления их в пространственный индекс:
// imports excluded public class SampleSpatialGraph { public static void main(String[] args) throws IOException { List<String> lines = readFile("/path/to/stadiums.csv"); EmbeddedGraphDatabase db = new EmbeddedGraphDatabase("/path/to/neo4j-community-1.9.M04/data/graph.db"); Index<Node> index = createSpatialIndex(db, "stadiumsLocation"); Transaction tx = db.beginTx(); for (String stadium : lines) { String[] columns = stadium.split(","); Node stadiumNode = db.createNode(); stadiumNode.setProperty("wkt", String.format("POINT(%s %s)", columns[4], columns[3])); stadiumNode.setProperty("name", columns[0]); index.add(stadiumNode, "dummy", "value"); } tx.success(); tx.finish(); } private static Index<Node> createSpatialIndex(EmbeddedGraphDatabase db, String indexName) { return db.index().forNodes(indexName, SpatialIndexProvider.SIMPLE_WKT_CONFIG); } // readFile function excluded }
Полный код приведен в этом разделе, если вам интересно.
Теперь мы можем запросить стадионы с помощью шифра, чтобы найти, скажем, стадионы в пределах 5 километров от Манчестера :
START n=node:stadiumsLocation('withinDistance:[53.489271,-2.246704, 5.0]') RETURN n.name, n.wkt;
==> +------------------------------------------------+ ==> | n.name | n.wkt | ==> +------------------------------------------------+ ==> | ""Etihad Stadium"" | "POINT(-2.20024 53.483)" | ==> | ""Old Trafford"" | "POINT(-2.29139 53.4631)" | ==> +------------------------------------------------+ ==> 2 rows ==> 224 ms
Или мы можем использовать запрос ограничивающего прямоугольника, посредством которого мы возвращаем все стадионы в виртуальном прямоугольнике на основе координат. Например, следующий запрос возвращает все стадионы, которые находятся в пределах M25:
START n=node:stadiumsLocation('bbox:[-0.519104,0.22934,51.279958,51.69299]') RETURN n.name, n.wkt;
==> +----------------------------------------------------+ ==> | n.name | n.wkt | ==> +----------------------------------------------------+ ==> | ""White Hart Lane"" | "POINT(-0.065684 51.6033)" | ==> | ""Wembley"" | "POINT(-0.279543 51.5559)" | ==> | ""Victoria Road"" | "POINT(0.159739 51.5478)" | ==> | ""Vicarage Road"" | "POINT(-0.401569 51.6498)" | ==> | ""Underhill Stadium"" | "POINT(-0.191789 51.6464)" | ==> | ""The Valley"" | "POINT(0.036757 51.4865)" | ==> | ""The Den"" | "POINT(-0.050743 51.4859)" | ==> | ""Stamford Bridge"" | "POINT(-0.191034 51.4816)" | ==> | ""Selhurst Park"" | "POINT(-0.085455 51.3983)" | ==> | ""Craven Cottage"" | "POINT(-0.221619 51.4749)" | ==> | ""Griffin Park"" | "POINT(-0.302621 51.4882)" | ==> | ""Loftus Road"" | "POINT(-0.232204 51.5093)" | ==> | ""Boleyn Ground"" | "POINT(0.039225 51.5321)" | ==> | ""Emirates Stadium"" | "POINT(-0.108436 51.5549)" | ==> | ""Brisbane Road"" | "POINT(-0.012551 51.5601)" | ==> +----------------------------------------------------+ ==> 15 rows ==> 23 ms
Теперь мне просто нужно связать стадионы с остальной частью графика, и я смогу писать запросы, основанные на производительности игроков в разных частях страны.