ricgraph 3.2__tar.gz → 3.3__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.
- {ricgraph-3.2/ricgraph.egg-info → ricgraph-3.3}/PKG-INFO +1 -1
- {ricgraph-3.2 → ricgraph-3.3}/README.md +6 -55
- {ricgraph-3.2 → ricgraph-3.3}/pyproject.toml +1 -1
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph.py +18 -13
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_cache.py +36 -14
- ricgraph-3.3/ricgraph/ricgraph_constants.py +454 -0
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_cypher.py +397 -182
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_file.py +15 -4
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_graphdb.py +70 -65
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_harvest.py +202 -130
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_researchinfo.py +18 -20
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_restapi.py +1 -1
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/ricgraph_utils.py +88 -55
- {ricgraph-3.2 → ricgraph-3.3/ricgraph.egg-info}/PKG-INFO +1 -1
- ricgraph-3.2/ricgraph/ricgraph_constants.py +0 -210
- {ricgraph-3.2 → ricgraph-3.3}/LICENSE +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/README-PyPI.md +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph/__init__.py +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph.egg-info/SOURCES.txt +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph.egg-info/dependency_links.txt +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph.egg-info/requires.txt +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/ricgraph.egg-info/top_level.txt +0 -0
- {ricgraph-3.2 → ricgraph-3.3}/setup.cfg +0 -0
|
@@ -23,7 +23,9 @@ We use color=#4c1 (green), that color is used by the 'repo status' badge.
|
|
|
23
23
|
Documentation about the Podman badges can be found here: https://github.com/eggplants/ghcr-badge.
|
|
24
24
|
--->
|
|
25
25
|
|
|
26
|
-
>
|
|
26
|
+
> [Use Ricgraph](https://www.ricgraph.eu/pilot-project-open-ricgraph-demo-server.html).
|
|
27
|
+
> [Read news about Ricgraph](https://www.ricgraph.eu/ricgraph-news.html).
|
|
28
|
+
> Read the [Tutorial](https://docs.ricgraph.eu/docs/ricgraph_tutorial.html).
|
|
27
29
|
> Go to the [Documentation website](https://docs.ricgraph.eu).
|
|
28
30
|
> Consult the [Table of contents](docs/ricgraph_toc_documentation.md#table-of-contents-ricgraph-documentation),
|
|
29
31
|
> or the [Index](docs/ricgraph_index_documentation.md#index-ricgraph-documentation).
|
|
@@ -84,58 +86,6 @@ extensive one (also including the use cases).
|
|
|
84
86
|
</tr>
|
|
85
87
|
</table>
|
|
86
88
|
|
|
87
|
-
## Ricgraph news
|
|
88
|
-
|
|
89
|
-
Read my recent preprint:
|
|
90
|
-
|
|
91
|
-
* Rik D.T. Janssen (2025).
|
|
92
|
-
*Utilizing Ricgraph to gain insights into research collaborations across institutions,
|
|
93
|
-
at every organizational level*. Submitted to SoftwareX [preprint].
|
|
94
|
-
[https://doi.org/10.2139/ssrn.5524439](https://doi.org/10.2139/ssrn.5524439).
|
|
95
|
-
|
|
96
|
-
See Ricgraph in action:
|
|
97
|
-
|
|
98
|
-
* Use the Open Ricgraph demo server
|
|
99
|
-
via [https://explorer.ricgraph.eu](https://explorer.ricgraph.eu).
|
|
100
|
-
Read more (and join) at
|
|
101
|
-
[pilot project Open Ricgraph demo
|
|
102
|
-
server](https://www.ricgraph.eu/pilot-project-open-ricgraph-demo-server.html).
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
Currently, there are people working on the following extensions for Ricgraph:
|
|
106
|
-
|
|
107
|
-
* [BackToPure](https://github.com/UtrechtUniversity/backtopure)
|
|
108
|
-
is a tool designed to enhance an organization's
|
|
109
|
-
[Research Information System Pure](https://www.elsevier.com/solutions/pure)
|
|
110
|
-
by enriching its content. BackToPure can identify items
|
|
111
|
-
(such as publications, data sets or software)
|
|
112
|
-
that exist in other external sources but are missing from the organization's Pure,
|
|
113
|
-
and then insert (enrich) those items into Pure.
|
|
114
|
-
The result is a more complete overview of research at that organization.
|
|
115
|
-
Status: experimental stage (beta).
|
|
116
|
-
* A chatbot that allows you to "talk" to Ricgraph. You can formulate questions in
|
|
117
|
-
plain English, such as "Please give me the research results of the Geosciences
|
|
118
|
-
faculty of Utrecht University?"
|
|
119
|
-
or "With what organizations does that faculty collaborate?".
|
|
120
|
-
It uses a local Large Language Model.
|
|
121
|
-
Status: planning stage (pre-alpha).
|
|
122
|
-
* A project with six students from the University of Applied Sciences, Utrecht, that aims to
|
|
123
|
-
[create a general harvester for
|
|
124
|
-
Ricgraph](docs/ricgraph_outreach.md#ricgraph-projects-with-students).
|
|
125
|
-
It will remove a lot of code duplication in the harvest scripts, and will
|
|
126
|
-
make it easier to add new harvest sources.
|
|
127
|
-
Status: planning stage (pre-alpha).
|
|
128
|
-
* A project with a student from the University of Applied Sciences, Utrecht, that aims to use
|
|
129
|
-
[AI and Large Language Models to find topics and visualize large amounts of research
|
|
130
|
-
information](docs/ricgraph_outreach.md#ricgraph-projects-with-students).
|
|
131
|
-
It assigns *topics* to publications,
|
|
132
|
-
data sets, and software. By selecting a number of topics, research results are
|
|
133
|
-
grouped, and possibly experts on these topics can be found.
|
|
134
|
-
Status: planning stage (pre-alpha).
|
|
135
|
-
* A tool that helps Pure administrators to clean up "external organizations" in Pure.
|
|
136
|
-
Status: planning stage (pre-alpha).
|
|
137
|
-
|
|
138
|
-
|
|
139
89
|
## Motivation
|
|
140
90
|
|
|
141
91
|
Ricgraph is software that is about
|
|
@@ -403,7 +353,8 @@ The following figure shows how three persons have contributed to one research ou
|
|
|
403
353
|
|
|
404
354
|
### Steps to take if you would like to use Ricgraph
|
|
405
355
|
|
|
406
|
-
* Use
|
|
356
|
+
* [Use Ricgraph](https://www.ricgraph.eu/pilot-project-open-ricgraph-demo-server.html).
|
|
357
|
+
* Read more about [Ricgraph Explorer](docs/ricgraph_explorer.md#ricgraph-explorer),
|
|
407
358
|
the exploration tool for Ricgraph.
|
|
408
359
|
* Use the [Ricgraph REST API](docs/ricgraph_restapi.md#ricgraph-rest-api),
|
|
409
360
|
the REST API for Ricgraph.
|
|
@@ -449,4 +400,4 @@ please let me know by creating a GitHub *Issue* at the top left of that page.
|
|
|
449
400
|
<!-- Do not change the lines below. The version number will be
|
|
450
401
|
modified by script maintenance/update_version.bash -->
|
|
451
402
|
This README.md file is part of the
|
|
452
|
-
documentation for version 3.
|
|
403
|
+
documentation for version 3.3 of Ricgraph - Research in context graph.
|
|
@@ -90,7 +90,7 @@ In the default configuration of Ricgraph, the following properties are included:
|
|
|
90
90
|
|
|
91
91
|
- url_other: other URL for a node, pointing to e.g. the originating record in a source system.
|
|
92
92
|
|
|
93
|
-
- year: year of a research
|
|
93
|
+
- year: year of a research result.
|
|
94
94
|
|
|
95
95
|
- source_event: an event to be added to the _source list.
|
|
96
96
|
|
|
@@ -100,8 +100,8 @@ In the default configuration of Ricgraph, the following properties are included:
|
|
|
100
100
|
|
|
101
101
|
from numpy import nan
|
|
102
102
|
from pandas import DataFrame, concat, set_option
|
|
103
|
-
from typing import Union
|
|
104
103
|
|
|
104
|
+
from .ricgraph_constants import PERSON_CATEGORY_PERSON
|
|
105
105
|
from .ricgraph_utils import (timestamp, timestamp_posix,
|
|
106
106
|
print_records_per_minute,
|
|
107
107
|
print_progress)
|
|
@@ -120,7 +120,7 @@ __package__ = 'Ricgraph'
|
|
|
120
120
|
# __version__ should be placed here instead of in __init__.py.
|
|
121
121
|
# If not here, it cannot be found when executing something like
|
|
122
122
|
# PYTHONPATH=../ricgraph ../bin/python ricgraph_explorer.py
|
|
123
|
-
__version__ = '3.
|
|
123
|
+
__version__ = '3.3'
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
# ##############################################################################
|
|
@@ -164,7 +164,8 @@ def update_nodes_df(nodes: DataFrame) -> None:
|
|
|
164
164
|
if prop_name == other_name:
|
|
165
165
|
node_properties[prop_name] = getattr(row, other_name)
|
|
166
166
|
|
|
167
|
-
create_update_node(name=row.name, category=row.category,
|
|
167
|
+
create_update_node(name=str(row.name), category=str(row.category),
|
|
168
|
+
value=str(row.value),
|
|
168
169
|
other_properties=node_properties)
|
|
169
170
|
|
|
170
171
|
print_progress(count=count, now=True)
|
|
@@ -175,7 +176,7 @@ def update_nodes_df(nodes: DataFrame) -> None:
|
|
|
175
176
|
return
|
|
176
177
|
|
|
177
178
|
|
|
178
|
-
def create_nodepairs_and_edges_df(left_and_right_nodepairs: DataFrame) -> None:
|
|
179
|
+
def create_nodepairs_and_edges_df(left_and_right_nodepairs: DataFrame | None) -> None:
|
|
179
180
|
"""Create two nodes (called 'node pairs') and two directed edges between those nodes.
|
|
180
181
|
This is done for all the nodes passed. The nodes are specified in a DataFrame.
|
|
181
182
|
One row in the DataFrame contains two nodes which are to be connected.
|
|
@@ -187,6 +188,8 @@ def create_nodepairs_and_edges_df(left_and_right_nodepairs: DataFrame) -> None:
|
|
|
187
188
|
:param left_and_right_nodepairs: the node pairs in a DataFrame.
|
|
188
189
|
:return: None.
|
|
189
190
|
"""
|
|
191
|
+
if left_and_right_nodepairs is None or left_and_right_nodepairs.empty:
|
|
192
|
+
return
|
|
190
193
|
print('There are ' + str(len(left_and_right_nodepairs)) + ' rows ('
|
|
191
194
|
+ timestamp() + '), creating nodes and edges for row:')
|
|
192
195
|
count = 0
|
|
@@ -203,8 +206,10 @@ def create_nodepairs_and_edges_df(left_and_right_nodepairs: DataFrame) -> None:
|
|
|
203
206
|
if prop_name + '2' == other_name:
|
|
204
207
|
node_properties[prop_name + '2'] = getattr(row, other_name)
|
|
205
208
|
|
|
206
|
-
create_two_nodes_and_edge(name1=row.name1, category1=row.category1,
|
|
207
|
-
|
|
209
|
+
create_two_nodes_and_edge(name1=str(row.name1), category1=str(row.category1),
|
|
210
|
+
value1=str(row.value1),
|
|
211
|
+
name2=str(row.name2), category2=str(row.category2),
|
|
212
|
+
value2=str(row.value2),
|
|
208
213
|
**node_properties)
|
|
209
214
|
print_progress(count=count, now=True)
|
|
210
215
|
end_ts = timestamp_posix()
|
|
@@ -214,9 +219,9 @@ def create_nodepairs_and_edges_df(left_and_right_nodepairs: DataFrame) -> None:
|
|
|
214
219
|
return
|
|
215
220
|
|
|
216
221
|
|
|
217
|
-
def create_nodepairs_and_edges_params(name1:
|
|
218
|
-
name2:
|
|
219
|
-
**other_properties:
|
|
222
|
+
def create_nodepairs_and_edges_params(name1: dict | str, category1: dict | str, value1: dict | str,
|
|
223
|
+
name2: dict | str, category2: dict | str, value2: dict | str,
|
|
224
|
+
**other_properties: dict | str) -> None:
|
|
220
225
|
"""Create two nodes (called 'node pairs') and two directed edges between those nodes.
|
|
221
226
|
This is done for all the nodes passed. The nodes are specified by values passed to this function.
|
|
222
227
|
Each value can be either a string or a dict containing strings.
|
|
@@ -285,7 +290,7 @@ def create_nodepairs_and_edges_params(name1: Union[dict, str], category1: Union[
|
|
|
285
290
|
|
|
286
291
|
|
|
287
292
|
def unify_personal_identifiers(personal_identifiers: DataFrame,
|
|
288
|
-
source_event:
|
|
293
|
+
source_event: dict | str, history_event: dict | str) -> None:
|
|
289
294
|
"""Unify a collection of personal identifiers (e.g. ORCID, ISNI, etc.).
|
|
290
295
|
That means that every column is unified to every other column.
|
|
291
296
|
The identifiers are specified as columns in a DataFrame.
|
|
@@ -343,9 +348,9 @@ def unify_personal_identifiers(personal_identifiers: DataFrame,
|
|
|
343
348
|
identifiers.rename(columns={column1: 'value1',
|
|
344
349
|
column2: 'value2'}, inplace=True)
|
|
345
350
|
new_identifiers_columns = {'name1': column1,
|
|
346
|
-
'category1':
|
|
351
|
+
'category1': PERSON_CATEGORY_PERSON,
|
|
347
352
|
'name2': column2,
|
|
348
|
-
'category2':
|
|
353
|
+
'category2': PERSON_CATEGORY_PERSON,
|
|
349
354
|
'source_event1': source_event,
|
|
350
355
|
'history_event1': history_event,
|
|
351
356
|
'source_event2': source_event,
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
from sys import getsizeof
|
|
46
|
-
from typing import Optional
|
|
46
|
+
from typing import Optional, Tuple
|
|
47
47
|
from pymemcache.client.base import Client
|
|
48
48
|
from .ricgraph_constants import MAX_NODES_CACHE_KEY_ID
|
|
49
49
|
from .ricgraph_utils import (get_configfile_key_memcached_parameters,
|
|
@@ -126,12 +126,14 @@ def nodes_cache_key_id_create(key: str, elementid: str) -> None:
|
|
|
126
126
|
:param elementid: id of a node.
|
|
127
127
|
:return: None.
|
|
128
128
|
"""
|
|
129
|
-
global _nodes_cache_key_id, _memcached_available
|
|
129
|
+
global _nodes_cache_key_id, _memcached_available, _memcached_client
|
|
130
130
|
|
|
131
131
|
if key == '' or elementid == '':
|
|
132
132
|
return
|
|
133
133
|
|
|
134
134
|
if memcached_check_available():
|
|
135
|
+
if _memcached_client is None:
|
|
136
|
+
return
|
|
135
137
|
# The docs are unclear whether I need to serialize the key if I
|
|
136
138
|
# use flag allow_unicode_keys=True in Client() above.
|
|
137
139
|
# So I do serialize to be sure. Since keys cannot have spaces,
|
|
@@ -167,12 +169,14 @@ def nodes_cache_key_id_read(key: str) -> str:
|
|
|
167
169
|
:param key: _key of a node.
|
|
168
170
|
:return: The id of the node, or '' if not present.
|
|
169
171
|
"""
|
|
170
|
-
global _nodes_cache_key_id, _memcached_available
|
|
172
|
+
global _nodes_cache_key_id, _memcached_available, _memcached_client
|
|
171
173
|
|
|
172
174
|
if key == '':
|
|
173
175
|
return ''
|
|
174
176
|
|
|
175
177
|
if memcached_check_available():
|
|
178
|
+
if _memcached_client is None:
|
|
179
|
+
return ''
|
|
176
180
|
key_serialized = serialize_value(value=key.replace(' ', '_'))
|
|
177
181
|
try:
|
|
178
182
|
elementid_serialized = _memcached_client.get(key=key_serialized)
|
|
@@ -201,12 +205,14 @@ def nodes_cache_key_id_delete_key(key: str) -> None:
|
|
|
201
205
|
:param key: _key of a node.
|
|
202
206
|
:return: None.
|
|
203
207
|
"""
|
|
204
|
-
global _nodes_cache_key_id, _memcached_available
|
|
208
|
+
global _nodes_cache_key_id, _memcached_available, _memcached_client
|
|
205
209
|
|
|
206
210
|
if key == '':
|
|
207
211
|
return
|
|
208
212
|
|
|
209
213
|
if memcached_check_available():
|
|
214
|
+
if _memcached_client is None:
|
|
215
|
+
return
|
|
210
216
|
key_serialized = serialize_value(value=key.replace(' ', '_'))
|
|
211
217
|
try:
|
|
212
218
|
# Works regardless whether the key is present or not.
|
|
@@ -230,9 +236,11 @@ def nodes_cache_key_id_empty() -> None:
|
|
|
230
236
|
|
|
231
237
|
:return: None.
|
|
232
238
|
"""
|
|
233
|
-
global _nodes_cache_key_id, _memcached_available
|
|
239
|
+
global _nodes_cache_key_id, _memcached_available, _memcached_client
|
|
234
240
|
|
|
235
241
|
if memcached_check_available():
|
|
242
|
+
if _memcached_client is None:
|
|
243
|
+
return
|
|
236
244
|
try:
|
|
237
245
|
_memcached_client.flush_all()
|
|
238
246
|
except:
|
|
@@ -247,31 +255,45 @@ def nodes_cache_key_id_empty() -> None:
|
|
|
247
255
|
return
|
|
248
256
|
|
|
249
257
|
|
|
250
|
-
def
|
|
258
|
+
def nodes_cache_key_id_size() -> Tuple[int, float]:
|
|
251
259
|
"""Return the size of the cache for node id's.
|
|
252
260
|
'id' in this sentence is the id assigned by de graph database.
|
|
253
261
|
|
|
254
|
-
:return: a
|
|
262
|
+
:return: a tuple with number of items and size in kB.
|
|
255
263
|
"""
|
|
256
|
-
global _nodes_cache_key_id
|
|
264
|
+
global _nodes_cache_key_id, _memcached_client
|
|
257
265
|
|
|
258
266
|
if memcached_check_available():
|
|
259
|
-
|
|
267
|
+
if _memcached_client is None:
|
|
268
|
+
return 0, 0.0
|
|
260
269
|
try:
|
|
261
270
|
stats = _memcached_client.stats()
|
|
262
|
-
|
|
271
|
+
nr_items = int(stats.get(b'curr_items', 0))
|
|
263
272
|
bytes_used = int(stats.get(b'bytes', 0))
|
|
264
273
|
size_kb = round(bytes_used / 1000, 1)
|
|
265
274
|
except:
|
|
266
275
|
# In case the connection to Memcached is lost, we will also end up here,
|
|
267
276
|
# and we just continue.
|
|
268
|
-
|
|
277
|
+
nr_items = 0
|
|
269
278
|
size_kb = 0.0
|
|
270
279
|
else:
|
|
271
|
-
|
|
272
|
-
items = len(_nodes_cache_key_id)
|
|
280
|
+
nr_items = len(_nodes_cache_key_id)
|
|
273
281
|
size_kb = round(getsizeof(_nodes_cache_key_id) / 1000, 1)
|
|
282
|
+
return nr_items, size_kb
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def nodes_cache_key_id_type_size() -> str:
|
|
286
|
+
"""Return the size of the cache for node id's.
|
|
287
|
+
'id' in this sentence is the id assigned by de graph database.
|
|
288
|
+
|
|
289
|
+
:return: a sentence with the length of the cache and its size.
|
|
290
|
+
"""
|
|
291
|
+
nr_items, size_kb = nodes_cache_key_id_size()
|
|
292
|
+
if memcached_check_available():
|
|
293
|
+
result = 'Ricgraph uses Memcached as cache. '
|
|
294
|
+
else:
|
|
295
|
+
result = 'Ricgraph uses a local cache. '
|
|
274
296
|
|
|
275
|
-
result += 'This cache has ' + str(
|
|
297
|
+
result += 'This cache has ' + str(nr_items) + ' elements, and its size is '
|
|
276
298
|
result += str(size_kb) + ' kB.'
|
|
277
299
|
return result
|