由于在另一个Neo4j数据库中转换MySQL数据库,我创建了一个图形数据库作为分层树。转型运作良好。
在顶层存在标记为Root的节点,在第二级存在标记为Country的国家/地区。每个国家都有标有城市的第三级城市。每个城市都有一个标记为地址的地址子集。关系应该是,
(root)-[:IS_ROOT]->(country)-[:HAS_CITY]->(city)-[:HAS_ADDRESS]->(address)
后来,使用Spring Data Neo4j存储库,我试图查询没有结果的数据库。
对于MySQL数据库,我使用JDBC,对于Neo4j数据库,我使用前面提到的Spring Data Neo4j。
这是我用来创建Neo4j数据库的控制器,
@Controller("importer")
public class SakilaDbImportController {
private static final Logger logger = LoggerFactory.getLogger(SakilaDbImportController.class);
@Autowired
@Lazy
AddressNeoRepository addressRepo;
@Autowired
@Lazy
CityNeoRepository cityRepo;
@Autowired
@Lazy
CountryNeoRepository countryRepo;
@Autowired
@Lazy
RootRepository rootRepo;
@Autowired
Neo4jTemplate template;
@Autowired
SakilaDbApiClient client;
public SakilaDbImportController() {
}
@Transactional
public RootNeo createGraphDb() {
RootNeo root = doImportRoot();
return root;
}
@Transactional
public RootNeo importRoot() {
return doImportRoot();
}
private RootNeo doImportRoot() {
logger.debug("Importing root");
RootNeo root = new RootNeo("1", "Root");
root.addLabel("_Root");
//root.addLabel("Root");
System.out.println("root created " + root);
List<Country> data = client.readAllCountries();
if (data.isEmpty()) throw new RuntimeException("Data for Root not found.");
Map<CountryNeo, RoleIsRoot> roles = relateCountriesToRoot(root, data);
//template.save(root);
Set<CountryNeo> set = roles.keySet();
for(Iterator<CountryNeo> it = set.iterator(); it.hasNext();) {
root.isRoot(it.next());
}
rootRepo.save(root);
/*
for(RoleIsRoot role: roles){
template.save(role);
}
*/
return root;
}
private Map<CountryNeo, RoleIsRoot> relateCountriesToRoot(RootNeo root, List<Country> data) {
Map<CountryNeo, RoleIsRoot> roles = new HashMap<CountryNeo, RoleIsRoot>();
for (Country country : data) {
if(country.getCountry().equalsIgnoreCase("Canada"))
continue;
CountryNeo countryNeo = doImportCountryNeo(country);
RoleIsRoot role = root.isRoot(countryNeo, "IS_ROOT_OF");
System.out.println("RoleIsRoot: " + role);
roles.put(countryNeo, role);
}
return roles;
}
@Transactional
public CountryNeo importCountryNeo(Country country) {
return doImportCountryNeo(country);
}
private CountryNeo doImportCountryNeo(Country country) {
logger.debug("Importing countryNeo");
CountryNeo countryNeo = new CountryNeo(generateIndex(country.getCountryId()), country.getCountry());
countryNeo.addLabel("_Country");
//countryNeo.addLabel("Country");
System.out.println("new country: " + countryNeo);
List<City> data = client.readAllCitiesByCountry(country);
if (data.isEmpty()) throw new RuntimeException("Data for Country not found.");
Map<CityNeo, RoleHasCity> roles = relateCitiesToCountry(countryNeo, data);
Set<CityNeo> set = roles.keySet();
for(Iterator<CityNeo> it = set.iterator(); it.hasNext();) {
countryNeo.hasCity(it.next());
}
countryRepo.save(countryNeo);
/*
template.save(countryNeo);
for(RoleHasCity role: roles){
template.save(role);
}
*/
return countryNeo;
}
private Map<CityNeo, RoleHasCity> relateCitiesToCountry(CountryNeo countryNeo, List<City> data) {
Map<CityNeo, RoleHasCity> roles = new HashMap<CityNeo, RoleHasCity>();
for (City city : data) {
CityNeo cityNeo = doImportCityNeo(city);
RoleHasCity role = countryNeo.hasCity(cityNeo, "IS_CITY_FROM");
System.out.println("RoleHasCity: " + role);
roles.put(cityNeo, role);
}
return roles;
}
@Transactional
public CityNeo importCityNeo(City city) {
return doImportCityNeo(city);
}
private CityNeo doImportCityNeo(City city) {
logger.debug("Importing cityNeo");
CityNeo cityNeo = new CityNeo(generateIndex(city.getCityId()), city.getCity());
cityNeo.addLabel("_City");
//cityNeo.addLabel("City");
System.out.println("new city: " + cityNeo);
List<Address> data = client.readAllAddressesByCity(city);
if (data.isEmpty()) throw new RuntimeException("Data for City not found.");
Map<AddressNeo, RoleHasAddress> roles = relateAddressesToCity(cityNeo, data);
Set<AddressNeo> set = roles.keySet();
for(Iterator<AddressNeo> it = set.iterator(); it.hasNext();) {
cityNeo.hasAddress(it.next());
}
cityRepo.save(cityNeo);
/*
template.save(cityNeo);
for(RoleHasAddress role: roles){
template.save(role);
}
*/
return cityNeo;
}
private Map<AddressNeo, RoleHasAddress> relateAddressesToCity(CityNeo cityNeo, List<Address> data) {
Map<AddressNeo, RoleHasAddress> roles = new HashMap<AddressNeo, RoleHasAddress>();
for(Address address: data) {
AddressNeo addressNeo = doImportAddressNeo(address);
RoleHasAddress role = cityNeo.hasAddress(addressNeo, "IS_ADDRESS_IN");
System.out.println("RoleHasAddress: " + role);
roles.put(addressNeo, role);
}
return roles;
}
@Transactional
public AddressNeo importAddressNeo(Address address) {
return doImportAddressNeo(address);
}
private AddressNeo doImportAddressNeo(Address address) {
logger.debug("Importing addressNeo");
if (address == null) throw new RuntimeException("Address not found.");
AddressNeo addressNeo = new AddressNeo(generateIndex(address.getAddressId()), address.getAddress());
addressNeo.addLabel("_Address");
//addressNeo.addLabel("Address");
System.out.println("new address: " + addressNeo);
addressNeo.setPostalCode(address.getPostalCode());
addressRepo.save(addressNeo);
/*
template.save(addressNeo);
*/
return addressNeo;
}
private String generateIndex(int index) {
return String.valueOf(index);
}
}
这是使用存储库执行查询的服务
@Service
public class SakilaDbQueries {
@Autowired
@Lazy
AddressNeoRepository addressRepo;
@Autowired
@Lazy
CityNeoRepository cityRepo;
@Autowired
@Lazy
CountryNeoRepository countryRepo;
@Autowired
@Lazy
RootRepository rootRepo;
public SakilaDbQueries() {
}
public List<String> findAllCountryNames() {
CountryNeoData names = countryRepo.findAllCountryNames();
Collection<String> collection = names.getCountries();
List<String> list = new ArrayList<String>();
for(Iterator<String> it = collection.iterator(); it.hasNext(); ) {
list.add(it.next());
}
return list;
}
public List<CountryNeo> findAllCountries() {
Result<CountryNeo> result = countryRepo.findAll();
List<CountryNeo> list = new ArrayList<CountryNeo>();
for(Iterator<CountryNeo> it = result.iterator(); it.hasNext(); ) {
list.add(it.next());
}
return list;
}
}
作为一个例子,
这是NodeEntity Place作为通用的
@NodeEntity
public class Place {
@GraphId Long nodeId;
@Indexed(unique=true)
String id;
@Indexed(indexType=IndexType.FULLTEXT, indexName = "place")
String name;
@Labels
private Collection<String> labels = Collections.emptySet();
protected Place(String id, String name) {
this.id = id;
this.name = name;
}
protected Place() {
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addLabel(String label) {
HashSet<String> newLabels = new HashSet<>(this.labels);
if (newLabels.add(label)) this.labels = newLabels;
}
public void removeLabel(String label) {
HashSet<String> newLabels = new HashSet<>(this.labels);
if (newLabels.remove(label)) this.labels = newLabels;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Place place = (Place) o;
if (nodeId == null) return super.equals(o);
return nodeId.equals(place.nodeId);
}
@Override
public int hashCode() {
return nodeId != null ? nodeId.hashCode() : super.hashCode();
}
@Override
public String toString() {
return String.format("%s [%s]", name, id);
}
}
和CountryNeo扩展了Place,
@NodeEntity
public class CountryNeo extends Place {
@RelatedTo(type = "HAS_CITY", direction = Direction.OUTGOING)
Set<CityNeo> cities;
@Fetch @RelatedToVia(type = "IS_ROOT", direction = Direction.INCOMING)
Iterable<RoleIsRoot> roles;
public CountryNeo() {
}
public CountryNeo(String id, String name) {
super(id, name);
}
public Set<CityNeo> getCities() {
return cities;
}
public void hasCity(CityNeo city) {
if(cities == null)
cities = new HashSet<CityNeo>();
cities.add(city);
}
public RoleHasCity hasCity(CityNeo city, String roleName) {
return new RoleHasCity(this, city, roleName);
}
public Collection<RoleIsRoot> getRoles() {
Iterable<RoleIsRoot> allRoles = roles;
return allRoles == null ? Collections.<RoleIsRoot>emptyList() : IteratorUtil.asCollection(allRoles);
}
}
使用过的角色,
@RelationshipEntity(type = "HAS_CITY")
public class RoleHasCity {
@GraphId Long id;
@StartNode CountryNeo country;
@EndNode CityNeo city;
String name;
public RoleHasCity() {
}
public RoleHasCity(CountryNeo country, CityNeo city, String roleName) {
this.country = country;
this.city = city;
this.name = roleName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public CountryNeo getCountry() {
return country;
}
public void setCountry(CountryNeo country) {
this.country = country;
}
public CityNeo getCity() {
return city;
}
public void setCity(CityNeo city) {
this.city = city;
}
@Override
public String toString() {
return String.format("%s %s %s", city, name, country);
}
}
和存储库,
public interface CountryNeoRepository extends GraphRepository<CountryNeo> {
@Query("MATCH (n:CountryNeo) RETURN COLLECT(n.name) AS countries")
CountryNeoData findAllCountryNames();
@QueryResult
public class CountryNeoData {
Collection<String> countries = Collections.emptyList();
public Collection<String> getCountries() {
return countries;
}
}
}
这是主要的bean,
public class SakilaImporter {
private GraphDatabaseService graphDatabase;
private SakilaDbImportController importer;
private SakilaDbQueries queries;
public SakilaImporter(GraphDatabaseService graphDatabase,
SakilaDbImportController importer,
SakilaDbQueries queries) {
this.graphDatabase = graphDatabase;
this.importer = importer;
this.queries = queries;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
GraphDatabaseService graphDatabase = ctx.getBean("graphDatabaseService", GraphDatabaseService.class);
SakilaDbImportController importer = ctx.getBean("importer", SakilaDbImportController.class);
SakilaDbQueries queries = ctx.getBean("queries", SakilaDbQueries.class);
SakilaImporter sakilaImporter = new SakilaImporter(graphDatabase, importer, queries);
Transaction tx = graphDatabase.beginTx();
try {
sakilaImporter.createDatabase();
sakilaImporter.queryDatabase();
tx.success();
} finally {
tx.close();
}
ctx.close();
}
public void createDatabase() {
System.out.println("Importing data...");
final long start = System.currentTimeMillis();
RootNeo root = importer.createGraphDb();
if(root != null) {
final long time = System.currentTimeMillis() - start;
System.out.println("Import places took " + time + " ms.");
} else {
System.out.println("root: " + root);
}
}
public void queryDatabase() {
System.out.println();System.out.println();
System.out.println("List of countries.-");
List<CountryNeo> countries = queries.findAllCountries();
for(CountryNeo country: countries) {
System.out.println(country);
}
System.out.println();System.out.println();
System.out.println("List of country names.-");
List<String> names = queries.findAllCountryNames();
for(String name: names) {
System.out.println(name);
}
}
}
两个查询的结果都是一个空列表