pyneoinstance 1.1.2__tar.gz → 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/MANIFEST.in +1 -0
- {pyneoinstance-1.1.2/pyneoinstance.egg-info → pyneoinstance-2.0.2}/PKG-INFO +82 -9
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/README.md +79 -7
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/__init__.py +1 -1
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/database/neo4jdbms.py +386 -1
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2/pyneoinstance.egg-info}/PKG-INFO +82 -9
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance.egg-info/SOURCES.txt +2 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance.egg-info/requires.txt +1 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance.egg-info/top_level.txt +1 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyproject.toml +4 -3
- pyneoinstance-2.0.2/setup.py +5 -0
- pyneoinstance-2.0.2/test/__init__.py +3 -0
- pyneoinstance-2.0.2/test/context.py +8 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/cypher_queries.yaml +1 -1
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/test_neo4jdb.py +89 -1
- pyneoinstance-1.1.2/setup.py +0 -3
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/LICENSE +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/database/__init__.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/database/context.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/fileload/__init__.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/fileload/context.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/fileload/helpers.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/fileload/loadyaml.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/util/__init__.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance/util/functions.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/pyneoinstance.egg-info/dependency_links.txt +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/setup.cfg +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/load_files.yaml +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/movies.csv +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/people.csv +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/roles.csv +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/test.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/test_fileload.py +0 -0
- {pyneoinstance-1.1.2 → pyneoinstance-2.0.2}/test/test_util_functions.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyneoinstance
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Handle Neo4j read and write transactions
|
|
3
|
+
Version: 2.0.2
|
|
4
|
+
Summary: Handle Neo4j read and write transactions and provide methos for performing graph EDA
|
|
5
5
|
Author-email: "Jose A. Alvarado-Guzman" <jose.alvarado-guzman@neo4j.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
7
7
|
Version 3, 29 June 2007
|
|
@@ -688,19 +688,30 @@ License-File: LICENSE
|
|
|
688
688
|
Requires-Dist: neo4j>=5.0.0
|
|
689
689
|
Requires-Dist: pandas
|
|
690
690
|
Requires-Dist: PyYAML
|
|
691
|
+
Requires-Dist: pyvis
|
|
691
692
|
|
|
692
693
|
# PyNeoInstance Package
|
|
693
694
|
|
|
694
695
|
## What is it?
|
|
695
696
|
|
|
696
|
-
PyNeoInstance is a Python package that provides a user friendly API for submitting Cypher queries to Neo4j.
|
|
697
|
+
PyNeoInstance is a Python package that provides a user friendly API for submitting Cypher queries to Neo4j and performing Exploratory Data Analysis (EDA) of your graph.
|
|
698
|
+
|
|
697
699
|
It supports the following features:
|
|
698
700
|
|
|
699
|
-
-
|
|
700
|
-
-
|
|
701
|
-
-
|
|
702
|
-
-
|
|
703
|
-
-
|
|
701
|
+
- __<u>Read query</u>__: Submit a Cypher read query, with or without parameters, and get a Pandas Data Frame with the results.
|
|
702
|
+
- __<u>Write query</u>__: Submit a write Cypher query, with or without parameters, to update an existing database.
|
|
703
|
+
- __<u>Write queries</u>__: Submit a list of Cypher queries to update an existing database.
|
|
704
|
+
- __<u>Write query with data</u>__: Update a database based on a Pandas Data Frame and a Cypher query.
|
|
705
|
+
- __<u>Write queries with data</u>__: Update a database based on a Pandas Data Frame and a list of Cypher queries.
|
|
706
|
+
- __<u>Node label frequency</u>__: Get the distribution of the graph node labels.
|
|
707
|
+
- __<u>Multi label node frequency</u>__: Get the distribution of the graph multi label nodes.
|
|
708
|
+
- __<u>Relationship type frequency</u>__: Get the distribution of the graph relationship types.
|
|
709
|
+
- __<u>Relationship type source-target frequency</u>__: Get the distribution of relationship source and target.
|
|
710
|
+
- __<u>Node and relationship properties</u>__: Get information of all properties in the graph.
|
|
711
|
+
- __<u>Constraints</u>__: Get information of all constraints in the graph.
|
|
712
|
+
- __<u>Indexes</u>__: Get information of all indexes in the graph.
|
|
713
|
+
- __<u>Schema Visualization</u>__: Visualize the graph schema.
|
|
714
|
+
|
|
704
715
|
|
|
705
716
|
## How to install it?
|
|
706
717
|
|
|
@@ -921,7 +932,69 @@ person_load_result = graph.execute_write_query_with_data(
|
|
|
921
932
|
workers = 5
|
|
922
933
|
)
|
|
923
934
|
```
|
|
935
|
+
## Graph EDA
|
|
936
|
+
|
|
937
|
+
### Node Label Frequency
|
|
938
|
+
The get_node_label_freq method provides the frequency and relative frequency of all nodes in the graph. This method consider all node labels as single labels, if you want the distribution considering multiple labels use the get_node_multilabel_freq method.
|
|
939
|
+
```python
|
|
940
|
+
graph.get_node_label_freq(database='mydbname')
|
|
941
|
+
```
|
|
942
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/nodefreq.png" width="250">
|
|
943
|
+
|
|
944
|
+
### Relationship Type Frequency
|
|
945
|
+
The get_rela_type_freq method provides the frequency and relative frequency of all relationship types in the graph.
|
|
946
|
+
```python
|
|
947
|
+
graph.get_rela_type_freq(database='mydbname')
|
|
948
|
+
```
|
|
949
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/relaFreq.png" width="300">
|
|
950
|
+
|
|
951
|
+
### Relationship Source-Target Frequency
|
|
952
|
+
The get_rela_source_target_freq method provides the frequency and relative frequency of all relationship types considering the node label of the source and targets of the relationships.
|
|
953
|
+
```python
|
|
954
|
+
graph.get_rela_type_freq(database='mydbname')
|
|
955
|
+
```
|
|
956
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/relaSourceTargetFreq.png" width="300">
|
|
957
|
+
|
|
958
|
+
### Properties
|
|
959
|
+
The get_properties method provides information about all the nodes and relationships properties.
|
|
960
|
+
```python
|
|
961
|
+
graph.graph.get_properties(database='mydbname')
|
|
962
|
+
```
|
|
963
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/properties.png" width="350" hight="300">
|
|
964
|
+
|
|
965
|
+
### Constraints
|
|
966
|
+
The get_constraints method provides information about all the graph constraints.
|
|
967
|
+
```python
|
|
968
|
+
graph.get_constraints(database='mydbname')
|
|
969
|
+
```
|
|
970
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/constraints.png" width="350" hight="300">
|
|
971
|
+
|
|
972
|
+
### Indexes
|
|
973
|
+
The get_indexes method provides information about all the graph indexes.
|
|
974
|
+
```python
|
|
975
|
+
graph.get_indexes(database='mydbname')
|
|
976
|
+
```
|
|
977
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/indexes.png" width="450" hight="400">
|
|
978
|
+
|
|
979
|
+
### Schema Visualization
|
|
980
|
+
The graph.get_schema_visualization provides an interactive UI with the visualization of the graph schema with the ability to filter the schema. This UI can be access via a Notebook or HTML page. This visualization displays the node labels as string close to nodes, relationship types are only display on mouse hover.
|
|
981
|
+
|
|
982
|
+
```python
|
|
983
|
+
schema = graph.get_schema_visualization(database='mydbname')
|
|
984
|
+
schema.show('schema.html')
|
|
985
|
+
```
|
|
986
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/schema.png" width="450" hight="400">
|
|
987
|
+
|
|
988
|
+
To access the UI via HTTML page just set the parameter notebook to false in the show method and open the html file in your browser.
|
|
989
|
+
|
|
990
|
+
```python
|
|
991
|
+
schema = graph.get_schema_visualization(database='mydbname')
|
|
992
|
+
schema.show('schema.html',notebook=False)
|
|
993
|
+
```
|
|
994
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/schemaHtml.png" width="450" hight="400">
|
|
924
995
|
|
|
925
996
|
## More detailed examples
|
|
926
997
|
|
|
927
|
-
For more detailed examples please
|
|
998
|
+
For more detailed examples please refer to the following articles:
|
|
999
|
+
* Data ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
|
|
1000
|
+
* Graph EDA: [Performing graph EDA with the PyNeoInstance Python Package](https://medium.com/@jose.alvarado-guzman/0c0f6f230aa9)
|
|
@@ -2,14 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## What is it?
|
|
4
4
|
|
|
5
|
-
PyNeoInstance is a Python package that provides a user friendly API for submitting Cypher queries to Neo4j.
|
|
5
|
+
PyNeoInstance is a Python package that provides a user friendly API for submitting Cypher queries to Neo4j and performing Exploratory Data Analysis (EDA) of your graph.
|
|
6
|
+
|
|
6
7
|
It supports the following features:
|
|
7
8
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
9
|
+
- __<u>Read query</u>__: Submit a Cypher read query, with or without parameters, and get a Pandas Data Frame with the results.
|
|
10
|
+
- __<u>Write query</u>__: Submit a write Cypher query, with or without parameters, to update an existing database.
|
|
11
|
+
- __<u>Write queries</u>__: Submit a list of Cypher queries to update an existing database.
|
|
12
|
+
- __<u>Write query with data</u>__: Update a database based on a Pandas Data Frame and a Cypher query.
|
|
13
|
+
- __<u>Write queries with data</u>__: Update a database based on a Pandas Data Frame and a list of Cypher queries.
|
|
14
|
+
- __<u>Node label frequency</u>__: Get the distribution of the graph node labels.
|
|
15
|
+
- __<u>Multi label node frequency</u>__: Get the distribution of the graph multi label nodes.
|
|
16
|
+
- __<u>Relationship type frequency</u>__: Get the distribution of the graph relationship types.
|
|
17
|
+
- __<u>Relationship type source-target frequency</u>__: Get the distribution of relationship source and target.
|
|
18
|
+
- __<u>Node and relationship properties</u>__: Get information of all properties in the graph.
|
|
19
|
+
- __<u>Constraints</u>__: Get information of all constraints in the graph.
|
|
20
|
+
- __<u>Indexes</u>__: Get information of all indexes in the graph.
|
|
21
|
+
- __<u>Schema Visualization</u>__: Visualize the graph schema.
|
|
22
|
+
|
|
13
23
|
|
|
14
24
|
## How to install it?
|
|
15
25
|
|
|
@@ -230,7 +240,69 @@ person_load_result = graph.execute_write_query_with_data(
|
|
|
230
240
|
workers = 5
|
|
231
241
|
)
|
|
232
242
|
```
|
|
243
|
+
## Graph EDA
|
|
244
|
+
|
|
245
|
+
### Node Label Frequency
|
|
246
|
+
The get_node_label_freq method provides the frequency and relative frequency of all nodes in the graph. This method consider all node labels as single labels, if you want the distribution considering multiple labels use the get_node_multilabel_freq method.
|
|
247
|
+
```python
|
|
248
|
+
graph.get_node_label_freq(database='mydbname')
|
|
249
|
+
```
|
|
250
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/nodefreq.png" width="250">
|
|
251
|
+
|
|
252
|
+
### Relationship Type Frequency
|
|
253
|
+
The get_rela_type_freq method provides the frequency and relative frequency of all relationship types in the graph.
|
|
254
|
+
```python
|
|
255
|
+
graph.get_rela_type_freq(database='mydbname')
|
|
256
|
+
```
|
|
257
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/relaFreq.png" width="300">
|
|
258
|
+
|
|
259
|
+
### Relationship Source-Target Frequency
|
|
260
|
+
The get_rela_source_target_freq method provides the frequency and relative frequency of all relationship types considering the node label of the source and targets of the relationships.
|
|
261
|
+
```python
|
|
262
|
+
graph.get_rela_type_freq(database='mydbname')
|
|
263
|
+
```
|
|
264
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/relaSourceTargetFreq.png" width="300">
|
|
265
|
+
|
|
266
|
+
### Properties
|
|
267
|
+
The get_properties method provides information about all the nodes and relationships properties.
|
|
268
|
+
```python
|
|
269
|
+
graph.graph.get_properties(database='mydbname')
|
|
270
|
+
```
|
|
271
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/properties.png" width="350" hight="300">
|
|
272
|
+
|
|
273
|
+
### Constraints
|
|
274
|
+
The get_constraints method provides information about all the graph constraints.
|
|
275
|
+
```python
|
|
276
|
+
graph.get_constraints(database='mydbname')
|
|
277
|
+
```
|
|
278
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/constraints.png" width="350" hight="300">
|
|
279
|
+
|
|
280
|
+
### Indexes
|
|
281
|
+
The get_indexes method provides information about all the graph indexes.
|
|
282
|
+
```python
|
|
283
|
+
graph.get_indexes(database='mydbname')
|
|
284
|
+
```
|
|
285
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/indexes.png" width="450" hight="400">
|
|
286
|
+
|
|
287
|
+
### Schema Visualization
|
|
288
|
+
The graph.get_schema_visualization provides an interactive UI with the visualization of the graph schema with the ability to filter the schema. This UI can be access via a Notebook or HTML page. This visualization displays the node labels as string close to nodes, relationship types are only display on mouse hover.
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
schema = graph.get_schema_visualization(database='mydbname')
|
|
292
|
+
schema.show('schema.html')
|
|
293
|
+
```
|
|
294
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/schema.png" width="450" hight="400">
|
|
295
|
+
|
|
296
|
+
To access the UI via HTTML page just set the parameter notebook to false in the show method and open the html file in your browser.
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
schema = graph.get_schema_visualization(database='mydbname')
|
|
300
|
+
schema.show('schema.html',notebook=False)
|
|
301
|
+
```
|
|
302
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/schemaHtml.png" width="450" hight="400">
|
|
233
303
|
|
|
234
304
|
## More detailed examples
|
|
235
305
|
|
|
236
|
-
For more detailed examples please
|
|
306
|
+
For more detailed examples please refer to the following articles:
|
|
307
|
+
* Data ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
|
|
308
|
+
* Graph EDA: [Performing graph EDA with the PyNeoInstance Python Package](https://medium.com/@jose.alvarado-guzman/0c0f6f230aa9)
|
|
@@ -13,9 +13,11 @@ from typing import Optional, List, Dict, Any
|
|
|
13
13
|
from collections import defaultdict
|
|
14
14
|
import multiprocessing as mp
|
|
15
15
|
import logging
|
|
16
|
+
import re
|
|
16
17
|
import numpy as np
|
|
17
18
|
from pandas import DataFrame
|
|
18
19
|
from neo4j import GraphDatabase
|
|
20
|
+
from pyvis.network import Network
|
|
19
21
|
from neo4j.exceptions import ServiceUnavailable
|
|
20
22
|
from neo4j.exceptions import AuthError
|
|
21
23
|
from neo4j.exceptions import ClientError
|
|
@@ -168,7 +170,6 @@ class Neo4jInstance:
|
|
|
168
170
|
self.neo_info['encrypted'] = kwargs.get('encrypted') or ''
|
|
169
171
|
self.__results = defaultdict(int)
|
|
170
172
|
|
|
171
|
-
|
|
172
173
|
def execute_read_query(self, query: str,
|
|
173
174
|
database: Optional[str] = None,
|
|
174
175
|
parameters: Optional[Dict[str, Any]] = None
|
|
@@ -421,3 +422,387 @@ class Neo4jInstance:
|
|
|
421
422
|
result = self.execute_write_queries_with_data(
|
|
422
423
|
[query], data,database, partitions, parallel, workers, params)
|
|
423
424
|
return result
|
|
425
|
+
|
|
426
|
+
def get_node_label_freq(self, database: Optional[str] = None) -> DataFrame:
|
|
427
|
+
"""Use to obtain the graph node label frequency.
|
|
428
|
+
|
|
429
|
+
Parameters
|
|
430
|
+
----------
|
|
431
|
+
database : str, optional
|
|
432
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
433
|
+
If not provided the default database is going to be use.
|
|
434
|
+
|
|
435
|
+
Returns
|
|
436
|
+
-------
|
|
437
|
+
DataFrame
|
|
438
|
+
Pandas DataFrame object containing the frequency and relative
|
|
439
|
+
frequency of node labels.
|
|
440
|
+
|
|
441
|
+
Raises
|
|
442
|
+
------
|
|
443
|
+
ClientError
|
|
444
|
+
When APOC Library is not install correctly in your Neo4j
|
|
445
|
+
deployment.
|
|
446
|
+
"""
|
|
447
|
+
error_msg = """
|
|
448
|
+
APOC Library not detected.
|
|
449
|
+
Please install it before procceding.
|
|
450
|
+
"""
|
|
451
|
+
query = """
|
|
452
|
+
MATCH(n)
|
|
453
|
+
WITH count(*) AS nodeCount
|
|
454
|
+
CALL db.labels() YIELD label
|
|
455
|
+
CALL apoc.cypher.run('MATCH (:`'+label+'`) RETURN count(*) as freq',{}) YIELD value
|
|
456
|
+
WITH nodeCount,label,value.freq AS freq
|
|
457
|
+
WITH *, 10^3 AS scaleFactor, toFloat(freq)/toFloat(nodeCount) AS relFreq
|
|
458
|
+
RETURN label AS nodeLabel,
|
|
459
|
+
freq AS frequency,
|
|
460
|
+
round(relFreq*scaleFactor)/scaleFactor AS relativeFrequency
|
|
461
|
+
ORDER BY freq DESC
|
|
462
|
+
"""
|
|
463
|
+
with _get_driver(self.neo_info) as driver:
|
|
464
|
+
with _get_session(driver, database) as session:
|
|
465
|
+
try:
|
|
466
|
+
result = session.execute_read(
|
|
467
|
+
_read_transaction_function,query=query)
|
|
468
|
+
except ServiceUnavailable as exception:
|
|
469
|
+
raise ServiceUnavailable() from exception
|
|
470
|
+
except ClientError:
|
|
471
|
+
raise ClientError(error_msg)
|
|
472
|
+
return result
|
|
473
|
+
|
|
474
|
+
def get_node_multilabel_freq(self, database: Optional[str] = None) -> DataFrame:
|
|
475
|
+
"""Use to obtain the graph node multi-label frequency.
|
|
476
|
+
|
|
477
|
+
Parameters
|
|
478
|
+
----------
|
|
479
|
+
database : str, optional
|
|
480
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
481
|
+
If not provided the default database is going to be use.
|
|
482
|
+
|
|
483
|
+
Returns
|
|
484
|
+
-------
|
|
485
|
+
DataFrame
|
|
486
|
+
Pandas DataFrame object containing the frequency and relative
|
|
487
|
+
frequency of node with multiple labels.
|
|
488
|
+
|
|
489
|
+
Raises
|
|
490
|
+
------
|
|
491
|
+
ClientError
|
|
492
|
+
When APOC Library is not install correctly in your Neo4j
|
|
493
|
+
deployment.
|
|
494
|
+
"""
|
|
495
|
+
error_msg = """
|
|
496
|
+
APOC Library not detected.
|
|
497
|
+
Please install it before procceding.
|
|
498
|
+
"""
|
|
499
|
+
query = """
|
|
500
|
+
MATCH (n)
|
|
501
|
+
WITH labels(n) as nodeLabels
|
|
502
|
+
WHERE size(nodeLabels)>1
|
|
503
|
+
RETURN nodeLabels, count(*) as frequency
|
|
504
|
+
"""
|
|
505
|
+
with _get_driver(self.neo_info) as driver:
|
|
506
|
+
with _get_session(driver, database) as session:
|
|
507
|
+
try:
|
|
508
|
+
result = session.execute_read(
|
|
509
|
+
_read_transaction_function,query=query)
|
|
510
|
+
except ServiceUnavailable as exception:
|
|
511
|
+
raise ServiceUnavailable() from exception
|
|
512
|
+
except ClientError:
|
|
513
|
+
raise ClientError(error_msg)
|
|
514
|
+
return result
|
|
515
|
+
|
|
516
|
+
def get_rela_type_freq(self, database: Optional[str] = None) -> DataFrame:
|
|
517
|
+
"""Use to obtain the graph relationship type frequency.
|
|
518
|
+
|
|
519
|
+
Parameters
|
|
520
|
+
----------
|
|
521
|
+
database : str, optional
|
|
522
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
523
|
+
If not provided the default database is going to be use.
|
|
524
|
+
|
|
525
|
+
Returns
|
|
526
|
+
-------
|
|
527
|
+
DataFrame
|
|
528
|
+
Pandas DataFrame object containing the frequency and relative
|
|
529
|
+
frequency of relationship types.
|
|
530
|
+
|
|
531
|
+
Raises
|
|
532
|
+
------
|
|
533
|
+
ClientError
|
|
534
|
+
When APOC Library is not install correctly in your Neo4j
|
|
535
|
+
deployment.
|
|
536
|
+
"""
|
|
537
|
+
error_msg = """
|
|
538
|
+
APOC Library not detected.
|
|
539
|
+
Please install it before procceding.
|
|
540
|
+
"""
|
|
541
|
+
query = """
|
|
542
|
+
MATCH()-[]->()
|
|
543
|
+
WITH count(*) AS relCount
|
|
544
|
+
CALL db.relationshipTypes() YIELD relationshipType as type
|
|
545
|
+
CALL apoc.cypher.run('MATCH ()-[:`'+type+'`]->() RETURN count(*) as freq',{})
|
|
546
|
+
YIELD value
|
|
547
|
+
WITH type AS relationshipType, value.freq AS freq,relCount
|
|
548
|
+
WITH *,3 AS presicion
|
|
549
|
+
WITH *, 10^presicion AS factor,toFloat(freq)/toFloat(relCount) as relFreq
|
|
550
|
+
RETURN relationshipType, freq AS frequency,
|
|
551
|
+
round(relFreq*factor)/factor AS relativeFrequency
|
|
552
|
+
ORDER BY freq DESC;
|
|
553
|
+
"""
|
|
554
|
+
with _get_driver(self.neo_info) as driver:
|
|
555
|
+
with _get_session(driver, database) as session:
|
|
556
|
+
try:
|
|
557
|
+
result = session.execute_read(
|
|
558
|
+
_read_transaction_function,query=query)
|
|
559
|
+
except ServiceUnavailable as exception:
|
|
560
|
+
raise ServiceUnavailable() from exception
|
|
561
|
+
except ClientError:
|
|
562
|
+
raise ClientError(error_msg)
|
|
563
|
+
return result
|
|
564
|
+
|
|
565
|
+
def get_properties(self, database: Optional[str] = None) -> DataFrame:
|
|
566
|
+
"""Use to obtain the node and relationship properties.
|
|
567
|
+
|
|
568
|
+
Parameters
|
|
569
|
+
----------
|
|
570
|
+
database : str, optional
|
|
571
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
572
|
+
If not provided the default database is going to be use.
|
|
573
|
+
|
|
574
|
+
Returns
|
|
575
|
+
-------
|
|
576
|
+
DataFrame
|
|
577
|
+
Pandas DataFrame object containing information about all nodes
|
|
578
|
+
and relationships properties.
|
|
579
|
+
|
|
580
|
+
Raises
|
|
581
|
+
------
|
|
582
|
+
ClientError
|
|
583
|
+
When APOC Library is not install correctly in your Neo4j
|
|
584
|
+
deployment.
|
|
585
|
+
"""
|
|
586
|
+
error_msg = """
|
|
587
|
+
APOC Library not detected.
|
|
588
|
+
Please install it before procceding.
|
|
589
|
+
"""
|
|
590
|
+
query = """
|
|
591
|
+
CALL apoc.meta.data() YIELD label,property,type,elementType
|
|
592
|
+
WHERE type<>'RELATIONSHIP'
|
|
593
|
+
RETURN elementType,label,property,type
|
|
594
|
+
ORDER BY elementType,label,property;
|
|
595
|
+
"""
|
|
596
|
+
with _get_driver(self.neo_info) as driver:
|
|
597
|
+
with _get_session(driver, database) as session:
|
|
598
|
+
try:
|
|
599
|
+
result = session.execute_read(
|
|
600
|
+
_read_transaction_function,query=query)
|
|
601
|
+
except ServiceUnavailable as exception:
|
|
602
|
+
raise ServiceUnavailable() from exception
|
|
603
|
+
except ClientError:
|
|
604
|
+
raise ClientError(error_msg)
|
|
605
|
+
return result
|
|
606
|
+
|
|
607
|
+
def get_constraints(self, database: Optional[str] = None) -> DataFrame:
|
|
608
|
+
"""Use to obtain the constraints in the graph.
|
|
609
|
+
|
|
610
|
+
Parameters
|
|
611
|
+
----------
|
|
612
|
+
database : str, optional
|
|
613
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
614
|
+
If not provided the default database is going to be use.
|
|
615
|
+
|
|
616
|
+
Returns
|
|
617
|
+
-------
|
|
618
|
+
DataFrame
|
|
619
|
+
Pandas DataFrame object containing information about all the
|
|
620
|
+
constraints.
|
|
621
|
+
|
|
622
|
+
Raises
|
|
623
|
+
------
|
|
624
|
+
ClientError
|
|
625
|
+
When APOC Library is not install correctly in your Neo4j
|
|
626
|
+
deployment.
|
|
627
|
+
"""
|
|
628
|
+
error_msg = """
|
|
629
|
+
APOC Library not detected.
|
|
630
|
+
Please install it before procceding.
|
|
631
|
+
"""
|
|
632
|
+
query = """
|
|
633
|
+
SHOW CONSTRAINTS
|
|
634
|
+
"""
|
|
635
|
+
with _get_driver(self.neo_info) as driver:
|
|
636
|
+
with _get_session(driver, database) as session:
|
|
637
|
+
try:
|
|
638
|
+
result = session.execute_read(
|
|
639
|
+
_read_transaction_function,query=query)
|
|
640
|
+
except ServiceUnavailable as exception:
|
|
641
|
+
raise ServiceUnavailable() from exception
|
|
642
|
+
except ClientError:
|
|
643
|
+
raise ClientError(error_msg)
|
|
644
|
+
return result
|
|
645
|
+
|
|
646
|
+
def get_indexes(self, database: Optional[str] = None) -> DataFrame:
|
|
647
|
+
"""Use to obtain the indexes in the graph.
|
|
648
|
+
|
|
649
|
+
Parameters
|
|
650
|
+
----------
|
|
651
|
+
database : str, optional
|
|
652
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
653
|
+
If not provided the default database is going to be use.
|
|
654
|
+
|
|
655
|
+
Returns
|
|
656
|
+
-------
|
|
657
|
+
DataFrame
|
|
658
|
+
Pandas DataFrame object containing information about all the
|
|
659
|
+
indexes.
|
|
660
|
+
|
|
661
|
+
Raises
|
|
662
|
+
------
|
|
663
|
+
ClientError
|
|
664
|
+
When APOC Library is not install correctly in your Neo4j
|
|
665
|
+
deployment.
|
|
666
|
+
"""
|
|
667
|
+
error_msg = """
|
|
668
|
+
APOC Library not detected.
|
|
669
|
+
Please install it before procceding.
|
|
670
|
+
"""
|
|
671
|
+
query = """
|
|
672
|
+
SHOW INDEX
|
|
673
|
+
"""
|
|
674
|
+
with _get_driver(self.neo_info) as driver:
|
|
675
|
+
with _get_session(driver, database) as session:
|
|
676
|
+
try:
|
|
677
|
+
result = session.execute_read(
|
|
678
|
+
_read_transaction_function,query=query)
|
|
679
|
+
except ServiceUnavailable as exception:
|
|
680
|
+
raise ServiceUnavailable() from exception
|
|
681
|
+
except ClientError:
|
|
682
|
+
raise ClientError(error_msg)
|
|
683
|
+
return result
|
|
684
|
+
|
|
685
|
+
def get_rela_source_target_freq(self, database: Optional[str] = None) -> DataFrame:
|
|
686
|
+
"""Use to obtain the relationships source and target frequency.
|
|
687
|
+
|
|
688
|
+
Parameters
|
|
689
|
+
----------
|
|
690
|
+
database : str, optional
|
|
691
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
692
|
+
If not provided the default database is going to be use.
|
|
693
|
+
|
|
694
|
+
Returns
|
|
695
|
+
-------
|
|
696
|
+
DataFrame
|
|
697
|
+
Pandas DataFrame object containing the frequency of
|
|
698
|
+
relationships cource and target frequency.
|
|
699
|
+
|
|
700
|
+
Raises
|
|
701
|
+
------
|
|
702
|
+
ClientError
|
|
703
|
+
When APOC Library is not install correctly in your Neo4j
|
|
704
|
+
deployment.
|
|
705
|
+
"""
|
|
706
|
+
error_msg = """
|
|
707
|
+
APOC Library not detected.
|
|
708
|
+
Please install it before procceding.
|
|
709
|
+
"""
|
|
710
|
+
query = """
|
|
711
|
+
CALL apoc.meta.stats() YIELD relTypes
|
|
712
|
+
"""
|
|
713
|
+
with _get_driver(self.neo_info) as driver:
|
|
714
|
+
with _get_session(driver, database) as session:
|
|
715
|
+
try:
|
|
716
|
+
result = session.execute_read(
|
|
717
|
+
_read_transaction_function,query=query)
|
|
718
|
+
except ServiceUnavailable as exception:
|
|
719
|
+
raise ServiceUnavailable() from exception
|
|
720
|
+
except ClientError:
|
|
721
|
+
raise ClientError(error_msg)
|
|
722
|
+
stat_dict = result.iloc[0,0]
|
|
723
|
+
stats_dicts = []
|
|
724
|
+
for key,value in stat_dict.items():
|
|
725
|
+
nodes = re.findall(r"\(:?(\w*)\)",key)
|
|
726
|
+
relationship = re.findall(r"\[:?(\w*)\]",key)[0]
|
|
727
|
+
info = {'sourceLabel':nodes[0],'relationshipType':relationship,'targetLabel':nodes[1],
|
|
728
|
+
'frequency':value}
|
|
729
|
+
stats_dicts.append(info)
|
|
730
|
+
stats_df = DataFrame(stats_dicts)
|
|
731
|
+
stats_df.sort_values(by=['relationshipType','sourceLabel','targetLabel'],inplace=True)
|
|
732
|
+
return stats_df
|
|
733
|
+
|
|
734
|
+
def get_schema_visualization(self, database: Optional[str] = None) -> Network:
|
|
735
|
+
"""Use to visualize the graph data model (schema).
|
|
736
|
+
|
|
737
|
+
Parameters
|
|
738
|
+
----------
|
|
739
|
+
database : str, optional
|
|
740
|
+
Name of the Neo4j database of which to execute the transaction.
|
|
741
|
+
If not provided the default database is going to be use.
|
|
742
|
+
|
|
743
|
+
Returns
|
|
744
|
+
-------
|
|
745
|
+
Network
|
|
746
|
+
Pyvis Network object containing the visualization information.
|
|
747
|
+
|
|
748
|
+
Raises
|
|
749
|
+
------
|
|
750
|
+
ClientError
|
|
751
|
+
When APOC Library is not install correctly in your Neo4j
|
|
752
|
+
deployment.
|
|
753
|
+
"""
|
|
754
|
+
error_msg = """
|
|
755
|
+
APOC Library not detected.
|
|
756
|
+
Please install it before procceding.
|
|
757
|
+
"""
|
|
758
|
+
query = """
|
|
759
|
+
CALL apoc.meta.schema() YIELD value
|
|
760
|
+
"""
|
|
761
|
+
with _get_driver(self.neo_info) as driver:
|
|
762
|
+
with _get_session(driver, database) as session:
|
|
763
|
+
try:
|
|
764
|
+
result = session.execute_read(
|
|
765
|
+
_read_transaction_function,query=query)
|
|
766
|
+
except ServiceUnavailable as exception:
|
|
767
|
+
raise ServiceUnavailable() from exception
|
|
768
|
+
except ClientError:
|
|
769
|
+
raise ClientError(error_msg)
|
|
770
|
+
schema = result.iloc[0,0]
|
|
771
|
+
network = Network(notebook=True,cdn_resources = "remote",directed=True,
|
|
772
|
+
filter_menu=True,height="800px", width="100%")
|
|
773
|
+
options = """
|
|
774
|
+
const options = {
|
|
775
|
+
"physics": {
|
|
776
|
+
"barnesHut": {
|
|
777
|
+
"gravitationalConstant": -13950,
|
|
778
|
+
"centralGravity": 6.15,
|
|
779
|
+
"springLength": 160,
|
|
780
|
+
"damping": 0.23
|
|
781
|
+
},
|
|
782
|
+
"minVelocity": 0.75
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
"""
|
|
786
|
+
network.set_options(options)
|
|
787
|
+
nodes = []
|
|
788
|
+
relationships = set()
|
|
789
|
+
for key in schema.keys():
|
|
790
|
+
if schema[key]['type']=='node':
|
|
791
|
+
nodes.append(key)
|
|
792
|
+
network.add_nodes(nodes)
|
|
793
|
+
for node in nodes:
|
|
794
|
+
for rel in schema[node]['relationships'].keys():
|
|
795
|
+
title = rel
|
|
796
|
+
if schema[node]['relationships'][rel]['direction']=='in':
|
|
797
|
+
target = node
|
|
798
|
+
for label in schema[node]['relationships'][rel]['labels']:
|
|
799
|
+
source = label
|
|
800
|
+
else:
|
|
801
|
+
source = node
|
|
802
|
+
for label in schema[node]['relationships'][rel]['labels']:
|
|
803
|
+
target = label
|
|
804
|
+
relationships.add(source + "|" + title + "|" + target)
|
|
805
|
+
for relationship in relationships:
|
|
806
|
+
rela_parts = relationship.split("|")
|
|
807
|
+
network.add_edge(rela_parts[0],rela_parts[2],title=rela_parts[1])
|
|
808
|
+
return network
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyneoinstance
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Handle Neo4j read and write transactions
|
|
3
|
+
Version: 2.0.2
|
|
4
|
+
Summary: Handle Neo4j read and write transactions and provide methos for performing graph EDA
|
|
5
5
|
Author-email: "Jose A. Alvarado-Guzman" <jose.alvarado-guzman@neo4j.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
7
7
|
Version 3, 29 June 2007
|
|
@@ -688,19 +688,30 @@ License-File: LICENSE
|
|
|
688
688
|
Requires-Dist: neo4j>=5.0.0
|
|
689
689
|
Requires-Dist: pandas
|
|
690
690
|
Requires-Dist: PyYAML
|
|
691
|
+
Requires-Dist: pyvis
|
|
691
692
|
|
|
692
693
|
# PyNeoInstance Package
|
|
693
694
|
|
|
694
695
|
## What is it?
|
|
695
696
|
|
|
696
|
-
PyNeoInstance is a Python package that provides a user friendly API for submitting Cypher queries to Neo4j.
|
|
697
|
+
PyNeoInstance is a Python package that provides a user friendly API for submitting Cypher queries to Neo4j and performing Exploratory Data Analysis (EDA) of your graph.
|
|
698
|
+
|
|
697
699
|
It supports the following features:
|
|
698
700
|
|
|
699
|
-
-
|
|
700
|
-
-
|
|
701
|
-
-
|
|
702
|
-
-
|
|
703
|
-
-
|
|
701
|
+
- __<u>Read query</u>__: Submit a Cypher read query, with or without parameters, and get a Pandas Data Frame with the results.
|
|
702
|
+
- __<u>Write query</u>__: Submit a write Cypher query, with or without parameters, to update an existing database.
|
|
703
|
+
- __<u>Write queries</u>__: Submit a list of Cypher queries to update an existing database.
|
|
704
|
+
- __<u>Write query with data</u>__: Update a database based on a Pandas Data Frame and a Cypher query.
|
|
705
|
+
- __<u>Write queries with data</u>__: Update a database based on a Pandas Data Frame and a list of Cypher queries.
|
|
706
|
+
- __<u>Node label frequency</u>__: Get the distribution of the graph node labels.
|
|
707
|
+
- __<u>Multi label node frequency</u>__: Get the distribution of the graph multi label nodes.
|
|
708
|
+
- __<u>Relationship type frequency</u>__: Get the distribution of the graph relationship types.
|
|
709
|
+
- __<u>Relationship type source-target frequency</u>__: Get the distribution of relationship source and target.
|
|
710
|
+
- __<u>Node and relationship properties</u>__: Get information of all properties in the graph.
|
|
711
|
+
- __<u>Constraints</u>__: Get information of all constraints in the graph.
|
|
712
|
+
- __<u>Indexes</u>__: Get information of all indexes in the graph.
|
|
713
|
+
- __<u>Schema Visualization</u>__: Visualize the graph schema.
|
|
714
|
+
|
|
704
715
|
|
|
705
716
|
## How to install it?
|
|
706
717
|
|
|
@@ -921,7 +932,69 @@ person_load_result = graph.execute_write_query_with_data(
|
|
|
921
932
|
workers = 5
|
|
922
933
|
)
|
|
923
934
|
```
|
|
935
|
+
## Graph EDA
|
|
936
|
+
|
|
937
|
+
### Node Label Frequency
|
|
938
|
+
The get_node_label_freq method provides the frequency and relative frequency of all nodes in the graph. This method consider all node labels as single labels, if you want the distribution considering multiple labels use the get_node_multilabel_freq method.
|
|
939
|
+
```python
|
|
940
|
+
graph.get_node_label_freq(database='mydbname')
|
|
941
|
+
```
|
|
942
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/nodefreq.png" width="250">
|
|
943
|
+
|
|
944
|
+
### Relationship Type Frequency
|
|
945
|
+
The get_rela_type_freq method provides the frequency and relative frequency of all relationship types in the graph.
|
|
946
|
+
```python
|
|
947
|
+
graph.get_rela_type_freq(database='mydbname')
|
|
948
|
+
```
|
|
949
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/relaFreq.png" width="300">
|
|
950
|
+
|
|
951
|
+
### Relationship Source-Target Frequency
|
|
952
|
+
The get_rela_source_target_freq method provides the frequency and relative frequency of all relationship types considering the node label of the source and targets of the relationships.
|
|
953
|
+
```python
|
|
954
|
+
graph.get_rela_type_freq(database='mydbname')
|
|
955
|
+
```
|
|
956
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/relaSourceTargetFreq.png" width="300">
|
|
957
|
+
|
|
958
|
+
### Properties
|
|
959
|
+
The get_properties method provides information about all the nodes and relationships properties.
|
|
960
|
+
```python
|
|
961
|
+
graph.graph.get_properties(database='mydbname')
|
|
962
|
+
```
|
|
963
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/properties.png" width="350" hight="300">
|
|
964
|
+
|
|
965
|
+
### Constraints
|
|
966
|
+
The get_constraints method provides information about all the graph constraints.
|
|
967
|
+
```python
|
|
968
|
+
graph.get_constraints(database='mydbname')
|
|
969
|
+
```
|
|
970
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/constraints.png" width="350" hight="300">
|
|
971
|
+
|
|
972
|
+
### Indexes
|
|
973
|
+
The get_indexes method provides information about all the graph indexes.
|
|
974
|
+
```python
|
|
975
|
+
graph.get_indexes(database='mydbname')
|
|
976
|
+
```
|
|
977
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/indexes.png" width="450" hight="400">
|
|
978
|
+
|
|
979
|
+
### Schema Visualization
|
|
980
|
+
The graph.get_schema_visualization provides an interactive UI with the visualization of the graph schema with the ability to filter the schema. This UI can be access via a Notebook or HTML page. This visualization displays the node labels as string close to nodes, relationship types are only display on mouse hover.
|
|
981
|
+
|
|
982
|
+
```python
|
|
983
|
+
schema = graph.get_schema_visualization(database='mydbname')
|
|
984
|
+
schema.show('schema.html')
|
|
985
|
+
```
|
|
986
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/schema.png" width="450" hight="400">
|
|
987
|
+
|
|
988
|
+
To access the UI via HTTML page just set the parameter notebook to false in the show method and open the html file in your browser.
|
|
989
|
+
|
|
990
|
+
```python
|
|
991
|
+
schema = graph.get_schema_visualization(database='mydbname')
|
|
992
|
+
schema.show('schema.html',notebook=False)
|
|
993
|
+
```
|
|
994
|
+
<img src="https://s3.amazonaws.com/neo4j-ps-ds-bootcamp/img/schemaHtml.png" width="450" hight="400">
|
|
924
995
|
|
|
925
996
|
## More detailed examples
|
|
926
997
|
|
|
927
|
-
For more detailed examples please
|
|
998
|
+
For more detailed examples please refer to the following articles:
|
|
999
|
+
* Data ingestion: [PyNeoInstance: A User-Friendly Python Library for Neo4j](https://medium.com/@a-gilmore/pyneoinstance-a-user-friendly-python-library-for-neo4j-dbefa3117bb2).
|
|
1000
|
+
* Graph EDA: [Performing graph EDA with the PyNeoInstance Python Package](https://medium.com/@jose.alvarado-guzman/0c0f6f230aa9)
|
|
@@ -6,8 +6,8 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "pyneoinstance"
|
|
9
|
-
version = "
|
|
10
|
-
description = "Handle Neo4j read and write transactions"
|
|
9
|
+
version = "2.0.2"
|
|
10
|
+
description = "Handle Neo4j read and write transactions and provide methos for performing graph EDA"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [{ name = "Jose A. Alvarado-Guzman",email = "jose.alvarado-guzman@neo4j.com" }]
|
|
13
13
|
license = { file = "LICENSE" }
|
|
@@ -20,6 +20,7 @@ keywords = ["neo4j", "graph", "cypher"]
|
|
|
20
20
|
dependencies = [
|
|
21
21
|
"neo4j>=5.0.0",
|
|
22
22
|
"pandas",
|
|
23
|
-
"PyYAML"
|
|
23
|
+
"PyYAML",
|
|
24
|
+
"pyvis"
|
|
24
25
|
]
|
|
25
26
|
requires-python = ">=3.8"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Use to provide context to the test module"""
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
sys.path.insert(0, os.path.abspath(
|
|
5
|
+
os.path.join(os.path.dirname(__file__), '..')))
|
|
6
|
+
from pyneoinstance import fileload
|
|
7
|
+
from pyneoinstance import util
|
|
8
|
+
from pyneoinstance import database
|
|
@@ -28,7 +28,7 @@ queries:
|
|
|
28
28
|
MATCH(p:Person {personId:row.personId}),(m:Movie {movieId:row.movieId})
|
|
29
29
|
MERGE(p)-[r:ACTED_IN]->(m)
|
|
30
30
|
ON CREATE
|
|
31
|
-
SET r.
|
|
31
|
+
SET r.characters=split(row.characters,':')
|
|
32
32
|
create_actor: |
|
|
33
33
|
MERGE(p:Person:Actor {personId:$id})
|
|
34
34
|
ON CREATE
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
import os
|
|
10
10
|
import unittest
|
|
11
11
|
import pandas as pd
|
|
12
|
+
import pandas.testing as pd_testing
|
|
13
|
+
from neo4j.exceptions import ClientError
|
|
12
14
|
from .context import database
|
|
13
15
|
from .context import fileload
|
|
14
16
|
from . import test_dir
|
|
@@ -24,6 +26,12 @@ class TestNeo4jInstance(unittest.TestCase):
|
|
|
24
26
|
test_neo4j_instance()
|
|
25
27
|
Test all the methods in the Neo4jInstance class.
|
|
26
28
|
"""
|
|
29
|
+
def assertDataframeEqual(self, a, b, msg):
|
|
30
|
+
try:
|
|
31
|
+
pd_testing.assert_frame_equal(a, b)
|
|
32
|
+
except AssertionError as e:
|
|
33
|
+
raise self.failureException(msg) from e
|
|
34
|
+
|
|
27
35
|
def setUp(self):
|
|
28
36
|
"""Set authentication variables and create Neo4j driver connection."""
|
|
29
37
|
try:
|
|
@@ -37,10 +45,11 @@ class TestNeo4jInstance(unittest.TestCase):
|
|
|
37
45
|
self.yaml_file = os.path.join(
|
|
38
46
|
test_dir,'cypher_queries.yaml')
|
|
39
47
|
self.queries = fileload.load_yaml_file(self.yaml_file,required_keys)
|
|
48
|
+
self.addTypeEqualityFunc(pd.DataFrame, self.assertDataframeEqual)
|
|
40
49
|
|
|
41
50
|
def tearDown(self):
|
|
42
51
|
"""Close the neo4j driver and delete the test data."""
|
|
43
|
-
queries = ["CALL apoc.schema.assert({},{})","MATCH(n) DELETE n"]
|
|
52
|
+
queries = ["CALL apoc.schema.assert({},{})","MATCH(n) DETACH DELETE n"]
|
|
44
53
|
self.graph.execute_write_queries(queries, self.queries['database'])
|
|
45
54
|
|
|
46
55
|
def test_neo4j_instance(self):
|
|
@@ -109,5 +118,84 @@ class TestNeo4jInstance(unittest.TestCase):
|
|
|
109
118
|
'properties_set':4}
|
|
110
119
|
self.assertEqual(solution, result)
|
|
111
120
|
|
|
121
|
+
# Test get_node_labels_freq
|
|
122
|
+
print('Get node labels freq')
|
|
123
|
+
role_file = os.path.join(test_dir,'roles.csv')
|
|
124
|
+
role_df = pd.read_csv(role_file)
|
|
125
|
+
result = self.graph.get_node_label_freq(
|
|
126
|
+
self.queries['database'])
|
|
127
|
+
solution = pd.DataFrame([
|
|
128
|
+
{'nodeLabel':'Person','frequency':18727,'relativeFrequency':.75},
|
|
129
|
+
{'nodeLabel':'Movie','frequency':6231,'relativeFrequency':.25},
|
|
130
|
+
{'nodeLabel':'Actor','frequency':1,'relativeFrequency':.00}
|
|
131
|
+
])
|
|
132
|
+
self.assertEqual(result,solution)
|
|
133
|
+
|
|
134
|
+
# Test get_node_multilabels_freq
|
|
135
|
+
print('Get node multilabel freq')
|
|
136
|
+
result = self.graph.get_node_multilabel_freq(
|
|
137
|
+
self.queries['database'])
|
|
138
|
+
solution = pd.DataFrame([
|
|
139
|
+
{'nodeLabels':['Person','Actor'],'frequency':1}])
|
|
140
|
+
self.assertEqual(result,solution)
|
|
141
|
+
|
|
142
|
+
# Test get_rela_labels_freq
|
|
143
|
+
print('Get relationship type freq')
|
|
144
|
+
self.graph.execute_write_query_with_data(
|
|
145
|
+
self.queries['queries']['load_role'],
|
|
146
|
+
role_df,
|
|
147
|
+
self.queries['database'])
|
|
148
|
+
result = self.graph.get_rela_type_freq(
|
|
149
|
+
self.queries['database'])
|
|
150
|
+
solution = pd.DataFrame([
|
|
151
|
+
{'relationshipType':'ACTED_IN','frequency':56914,'relativeFrequency':1.0}])
|
|
152
|
+
self.assertEqual(result,solution)
|
|
153
|
+
|
|
154
|
+
# Test get_properties
|
|
155
|
+
print('Get properties')
|
|
156
|
+
query = """
|
|
157
|
+
CALL apoc.meta.data() YIELD label,property,type,elementType
|
|
158
|
+
WHERE type<>'RELATIONSHIP'
|
|
159
|
+
RETURN elementType,label,property,type
|
|
160
|
+
ORDER BY elementType,label,property;
|
|
161
|
+
"""
|
|
162
|
+
solution = self.graph.execute_read_query(query,self.queries['database'])
|
|
163
|
+
result = self.graph.get_properties(
|
|
164
|
+
self.queries['database'])
|
|
165
|
+
self.assertEqual(result,solution)
|
|
166
|
+
|
|
167
|
+
# Test constraints
|
|
168
|
+
print('Get constraints')
|
|
169
|
+
query = """
|
|
170
|
+
SHOW CONSTRAINTS
|
|
171
|
+
"""
|
|
172
|
+
solution = self.graph.execute_read_query(query,self.queries['database'])
|
|
173
|
+
result = self.graph.get_constraints(
|
|
174
|
+
self.queries['database'])
|
|
175
|
+
self.assertEqual(result,solution)
|
|
176
|
+
|
|
177
|
+
# Test indexes
|
|
178
|
+
print('Get indexes')
|
|
179
|
+
query = """
|
|
180
|
+
SHOW INDEX
|
|
181
|
+
"""
|
|
182
|
+
solution = self.graph.execute_read_query(query,self.queries['database'])
|
|
183
|
+
result = self.graph.get_indexes(
|
|
184
|
+
self.queries['database'])
|
|
185
|
+
self.assertEqual(result,solution)
|
|
186
|
+
|
|
187
|
+
# Test indexes
|
|
188
|
+
print('Get rela details')
|
|
189
|
+
result = self.graph.get_rela_source_target_freq(
|
|
190
|
+
self.queries['database'])
|
|
191
|
+
solution = pd.DataFrame([
|
|
192
|
+
{'sourceLabel':'','relationshipType':'ACTED_IN','targetLabel':'','frequency':56914},
|
|
193
|
+
{'sourceLabel':'','relationshipType':'ACTED_IN','targetLabel':'Movie','frequency':56914},
|
|
194
|
+
{'sourceLabel':'Person','relationshipType':'ACTED_IN','targetLabel':'','frequency':56914}
|
|
195
|
+
]
|
|
196
|
+
)
|
|
197
|
+
solution.index = [2,0,1]
|
|
198
|
+
self.assertEqual(result,solution)
|
|
199
|
+
|
|
112
200
|
if __name__ == '__main__':
|
|
113
201
|
unittest.main()
|
pyneoinstance-1.1.2/setup.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|