Около недели назад я написал пост, в котором описал, как я добавил футбольные стадионы в свой футбольный график, используя neo4j пространственный, и после того, как я это сделал, я хотел включить его в свой скрипт импорта вместе с остальными данными.
Я подумал, что leiningen , вероятно, вполне подойдет для этого, поскольку вы можете указать его на класс Java и выполнить его.
Для начала мне пришлось немного изменить код импорта, чтобы связать стадионы с командами, которые уже добавлены в график:
package main.java; // imports excluded public class StadiumsImport { public static void main(String[] args) throws IOException { List<String> lines = readFile("data/stadiums.csv"); EmbeddedGraphDatabase db = new EmbeddedGraphDatabase("neo4j-community-1.9.M04/data/graph.db"); Index<Node> stadiumsIndex = createSpatialIndex(db, "stadiumsLocation"); Transaction tx = db.beginTx(); for (String stadium : lines) { String[] columns = stadium.split(","); Index<Node> teamsIndex = db.index().forNodes("teams"); String team = columns[1].replaceAll("\"",""); Node teamNode = teamsIndex.get("name", team).getSingle(); if(teamNode != null) { Node stadiumNode = db.createNode(); stadiumNode.setProperty("wkt", String.format("POINT(%s %s)", columns[4], columns[3])); stadiumNode.setProperty("name", columns[0].replaceAll("\"","")); stadiumsIndex.add(stadiumNode, "dummy", "value"); teamNode.createRelationshipTo(stadiumNode, DynamicRelationshipType.withName("play_at")); } } tx.success(); tx.finish(); } private static Index<Node> createSpatialIndex(EmbeddedGraphDatabase db, String indexName) { return db.index().forNodes(indexName, SpatialIndexProvider.SIMPLE_WKT_CONFIG); } // readFile excluded }
Я исключил некоторые биты кода для краткости , но он на этом суть , если вы заинтересованы.
Единственное изменение по сравнению с версией прошлой недели — это то, что мы сейчас ищем команду, которой принадлежит стадион, и создаем отношения play_at от команды к стадиону.
Затем я смог выполнить этот код, вызвав ‘lein run’ на основе следующего файла project.clj:
(defproject neo4jfootball "1.0.0-SNAPSHOT" :description "neo4j football project" :main "main.java.StadiumsImport" :dependencies [[org.clojure/clojure "1.4.0"] [org.neo4j/neo4j-spatial "0.11-SNAPSHOT"] [clojure-csv/clojure-csv "2.0.0-alpha1"]] :jvm-opts ["-Xmx2g"] :plugins [[lein-idea "1.0.1"]] :repositories {"local" ~(str (.toURI (java.io.File. "maven_repository")))} :java-source-paths ["src/main/java"] )
Я использую локальный репозиторий Maven для хранения JAR neo4j. Запись Maven была создана с помощью следующей команды, из которой я проверил пространственный проект neo4j :
mvn install:install-file -Dfile=target/neo4j-spatial-0.11-SNAPSHOT.jar -DartifactId=neo4j-spatial -Dversion=0.11-SNAPSHOT -DgroupId=org.neo4j -Dpackaging=jar -DlocalRepositoryPath=/path/to/neo4j-football/maven_repository -DpomFile=pom.xml
Это сработало достаточно хорошо, но я подумал, что было бы интересно посмотреть, как будет выглядеть приведенный выше код, если он будет написан в clojure.
Вот чем я закончил:
(ns neo4jfootball.core (:require [clojure-csv.core :as csv]) (:use clojure.java.io) (:import (org.neo4j.kernel EmbeddedGraphDatabase) (org.neo4j.gis.spatial.indexprovider SpatialIndexProvider) (org.neo4j.graphdb DynamicRelationshipType))) (defn take-csv [fname] (with-open [file (reader fname)] (csv/parse-csv (slurp file)))) (defn transform [line] {:stadium (get line 0) :team (get line 1) :lat (get line 3) :long (get line 4)}) (def not-nil? (comp not nil?)) (defn create-stadium-node [db line] (let [stadium-node (.. db createNode)] (.. stadium-node (setProperty "wkt" (format "POINT(%s %s)" (:long line) (:lat line)))) (.. stadium-node (setProperty "name" (:stadium line))) stadium-node)) (defn -main [] (do (let [db (new EmbeddedGraphDatabase "neo4j-community-1.9.M04/data/graph.db") tx (.beginTx db) stadiums-index (.. db index (forNodes "stadiumsLocation" (SpatialIndexProvider/SIMPLE_WKT_CONFIG))) teams-index (.. db index (forNodes "teams"))] (doseq [line (drop 1 (map transform (take-csv "data/stadiums.csv")))] (let [team-node (.. teams-index (get "name" (:team line)) getSingle)] (if (not-nil? team-node) (let [stadium-node (create-stadium-node db line)] (.. stadiums-index (add stadium-node "dummy" "value")) (.. team-node (createRelationshipTo stadium-node (DynamicRelationshipType/withName "play_at"))))))) (.. tx success) (.. tx finish))))
Код значительно упрощается благодаря использованию библиотеки CSV clojure, так что я мог бы достичь аналогичного в версии Java, используя эквивалентную библиотеку.
Немного проще увидеть, какие свойства строки в CSV-файле используются, где в результате функции преобразования мы конвертируем массив в карту.
Для достижения аналогичной цели в Java потребовалось бы немного больше кода, поэтому я не стал беспокоиться.
Страница Java Interop на сайте clojure была весьма полезна для разработки способов вызова различных методов в Java API.
В основном я использую макрос .., который позволяет нам связывать вызовы методов Java вместе. В нескольких случаях мы могли бы так же легко использовать . макрос вместо.
Затем мы можем назвать этот код из lein следующим образом:
lein run -m neo4jfootball.core