qlever 0.5.15__py3-none-any.whl → 0.5.18__py3-none-any.whl
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.
Potentially problematic release.
This version of qlever might be problematic. Click here for more details.
- qlever/Qleverfiles/Qleverfile.ohm-planet +15 -12
- qlever/Qleverfiles/Qleverfile.osm-planet +17 -15
- qlever/Qleverfiles/Qleverfile.uniprot +2 -3
- qlever/__init__.py +9 -4
- qlever/command.py +6 -5
- qlever/commands/add_text_index.py +47 -28
- qlever/commands/example_queries.py +138 -46
- qlever/commands/extract_queries.py +113 -0
- qlever/commands/index.py +41 -14
- qlever/commands/query.py +32 -3
- qlever/commands/settings.py +110 -0
- qlever/commands/start.py +215 -104
- qlever/commands/stop.py +39 -26
- qlever/commands/system_info.py +7 -3
- qlever/commands/ui.py +16 -4
- qlever/log.py +2 -1
- qlever/qlever_old.py +607 -369
- qlever/qleverfile.py +29 -6
- qlever/util.py +34 -17
- {qlever-0.5.15.dist-info → qlever-0.5.18.dist-info}/METADATA +2 -2
- {qlever-0.5.15.dist-info → qlever-0.5.18.dist-info}/RECORD +25 -23
- {qlever-0.5.15.dist-info → qlever-0.5.18.dist-info}/WHEEL +1 -1
- {qlever-0.5.15.dist-info → qlever-0.5.18.dist-info}/LICENSE +0 -0
- {qlever-0.5.15.dist-info → qlever-0.5.18.dist-info}/entry_points.txt +0 -0
- {qlever-0.5.15.dist-info → qlever-0.5.18.dist-info}/top_level.txt +0 -0
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
# Qleverfile for
|
|
1
|
+
# Qleverfile for OpenHistoricalMap, use with the QLever CLI (`pip install qlever`)
|
|
2
2
|
#
|
|
3
|
-
# qlever get-data # ~
|
|
4
|
-
# qlever index # ~
|
|
5
|
-
# qlever start #
|
|
3
|
+
# qlever get-data # ~1 hour, ~14 GB (ttl.gz), ~3.4 B triples (with osm2rdf)
|
|
4
|
+
# qlever index # ~1 hour, ~10 GB RAM, ~60 GB index size on disk
|
|
5
|
+
# qlever start # a few seconds, adjust MEMORY_FOR_QUERIES as needed
|
|
6
6
|
#
|
|
7
|
-
#
|
|
7
|
+
# Measured on an AMD Ryzen 9 5900X with 128 GB RAM and 1 x 4 TB NVMe (04.01.2025)
|
|
8
8
|
|
|
9
9
|
[data]
|
|
10
10
|
NAME = ohm-planet
|
|
11
11
|
GET_DATA_URL = https://planet.openhistoricalmap.org/planet
|
|
12
12
|
CHECK_BINARIES = osm2rdf -h > /dev/null || (echo "osm2rdf not found, make sure that it's installed and in your PATH" && exit 1)
|
|
13
|
-
GET_DATA_CMD_1 =
|
|
14
|
-
GET_DATA_CMD_2 = osm2rdf ${NAME}.pbf -o ${NAME}.ttl --source-dataset OHM --cache . --add-
|
|
15
|
-
GET_DATA_CMD =
|
|
13
|
+
GET_DATA_CMD_1 = unbuffer wget -O ${NAME}.pbf $$(curl -s ${GET_DATA_URL}/state.txt) 2>&1 | tee ${NAME}.download-log.txt
|
|
14
|
+
GET_DATA_CMD_2 = osm2rdf ${NAME}.pbf -o ${NAME}.ttl --source-dataset OHM --output-compression gz --store-locations=disk-dense --cache . --num-threads 12 --add-way-node-order --no-untagged-nodes-geometric-relations 2>&1 | tee ${NAME}.osm2rdf-log.txt
|
|
15
|
+
GET_DATA_CMD = ${CHECK_BINARIES} && ${GET_DATA_CMD_1} && echo && ${GET_DATA_CMD_2}
|
|
16
16
|
VERSION = $$(date -r ${NAME}.pbf +%d.%m.%Y || echo "NO_DATE")
|
|
17
17
|
DESCRIPTION = OHM Planet, data from ${GET_DATA_URL} version ${VERSION} (with GeoSPARQL predicates ogc:sfContains and ogc:sfIntersects)
|
|
18
18
|
|
|
19
19
|
[index]
|
|
20
|
-
INPUT_FILES
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
INPUT_FILES = ${data:NAME}.ttl.gz
|
|
21
|
+
MULTI_INPUT_JSON = { "cmd": "zcat ${INPUT_FILES}", "parallel": "true" }
|
|
22
|
+
STXXL_MEMORY = 5G
|
|
23
|
+
PARSER_BUFFER_SIZE = 50M
|
|
24
|
+
SETTINGS_JSON = { "num-triples-per-batch": 5000000 }
|
|
23
25
|
|
|
24
26
|
[server]
|
|
25
27
|
PORT = 7037
|
|
26
28
|
ACCESS_TOKEN = ${data:NAME}
|
|
27
29
|
MEMORY_FOR_QUERIES = 10G
|
|
28
30
|
CACHE_MAX_SIZE = 5G
|
|
31
|
+
TIMEOUT = 600s
|
|
29
32
|
CACHE_MAX_SIZE_SINGLE_ENTRY = 4G
|
|
30
|
-
WARMUP_CMD = curl -s https://qlever.cs.uni-freiburg.de/
|
|
33
|
+
WARMUP_CMD = curl -s https://qlever.cs.uni-freiburg.de/petrimaps/query --data-urlencode "query=PREFIX geo: <http://www.opengis.net/ont/geosparql#> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX osm: <https://www.openstreetmap.org/> SELECT ?osm_id ?geometry WHERE { ?osm_id geo:hasGeometry/geo:asWKT ?geometry . ?osm_id rdf:type osm:node } LIMIT 1" --data-urlencode "backend=https://qlever.cs.uni-freiburg.de/api/${data:NAME}" > /dev/null
|
|
31
34
|
|
|
32
35
|
[runtime]
|
|
33
36
|
SYSTEM = docker
|
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
# Qleverfile for OSM Planet, use with the
|
|
1
|
+
# Qleverfile for OSM Planet, use with the QLever CLI (`pip install qlever`)
|
|
2
2
|
#
|
|
3
|
-
# qlever get-data #
|
|
4
|
-
# qlever index #
|
|
5
|
-
# qlever start #
|
|
3
|
+
# qlever get-data # downloads ~400 GB (ttl.bz2), ~100 B triples
|
|
4
|
+
# qlever index # ~20 hours, ~60 GB RAM, ~1.5 TB index size on disk
|
|
5
|
+
# qlever start # a few seconds, adjust MEMORY_FOR_QUERIES as needed
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
# and edit the Qleverfile to specify the country,
|
|
7
|
+
# Measured on an AMD Ryzen 9 7950X with 128 GB RAM and 2 x 8 TB NVMe (04.01.2025)
|
|
9
8
|
|
|
10
9
|
[data]
|
|
11
10
|
NAME = osm-planet
|
|
12
11
|
DATA_URL = https://osm2rdf.cs.uni-freiburg.de/ttl/planet.osm.ttl.bz2
|
|
13
|
-
GET_DATA_CMD =
|
|
12
|
+
GET_DATA_CMD = unbuffer wget -O ${NAME}.ttl.bz2 ${DATA_URL} | tee ${NAME}.download-log.txt
|
|
14
13
|
VERSION = $$(date -r ${NAME}.ttl.bz2 +"%d.%m.%Y" || echo "NO_DATE")
|
|
15
14
|
DESCRIPTION = OSM Planet, data from ${DATA_URL} version ${VERSION} (complete OSM data, with GeoSPARQL predicates ogc:sfContains and ogc:sfIntersects)
|
|
16
15
|
|
|
17
16
|
[index]
|
|
18
|
-
INPUT_FILES
|
|
19
|
-
CAT_INPUT_FILES
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
INPUT_FILES = ${data:NAME}.ttl.bz2
|
|
18
|
+
CAT_INPUT_FILES = lbzcat -n 2 ${INPUT_FILES}
|
|
19
|
+
PARALLEL_PARSING = true
|
|
20
|
+
PARSER_BUFFER_SIZE = 100M
|
|
21
|
+
STXXL_MEMORY = 40G
|
|
22
|
+
SETTINGS_JSON = { "num-triples-per-batch": 10000000 }
|
|
23
|
+
ULIMIT = 10000
|
|
22
24
|
|
|
23
25
|
[server]
|
|
24
26
|
PORT = 7007
|
|
25
27
|
ACCESS_TOKEN = ${data:NAME}
|
|
26
|
-
MEMORY_FOR_QUERIES =
|
|
27
|
-
CACHE_MAX_SIZE =
|
|
28
|
-
CACHE_MAX_SIZE_SINGLE_ENTRY =
|
|
29
|
-
TIMEOUT =
|
|
28
|
+
MEMORY_FOR_QUERIES = 40G
|
|
29
|
+
CACHE_MAX_SIZE = 20G
|
|
30
|
+
CACHE_MAX_SIZE_SINGLE_ENTRY = 20G
|
|
31
|
+
TIMEOUT = 600s
|
|
30
32
|
|
|
31
33
|
[runtime]
|
|
32
34
|
SYSTEM = docker
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# qlever index # takes ~ 40 hours and ~ 60 GB RAM (on an AMD Ryzen 9 9950X)
|
|
5
5
|
# qlever start # starts the server (takes a few seconds)
|
|
6
6
|
#
|
|
7
|
-
# Install packages: sudo apt install -y libxml2-utils parallel xz-utils wget
|
|
7
|
+
# Install packages: sudo apt install -y libxml2-utils raptor2-utils parallel xz-utils wget
|
|
8
8
|
# Install manually: Apache Jena binaries (https://dlcdn.apache.org/jena/binaries)
|
|
9
9
|
#
|
|
10
10
|
# Set DATE to the date of the latest release. Build on SSD (requires ~ 7 TB
|
|
@@ -53,8 +53,7 @@ MULTI_INPUT_JSON = [{ "cmd": "zcat {}", "graph": "http://sparql.uniprot.org/unip
|
|
|
53
53
|
{ "cmd": "zcat ${data:TTL_DIR}/tissues.ttl.gz", "graph": "http://sparql.uniprot.org/tissues" },
|
|
54
54
|
{ "cmd": "zcat ${data:TTL_DIR}/rhea.ttl.gz", "graph": "https://sparql.rhea-db.org/rhea" },
|
|
55
55
|
{ "cmd": "zcat ${data:TTL_DIR}/examples_uniprot.ttl.gz", "graph": "http://sparql.uniprot.org/.well-known/sparql-examples" },
|
|
56
|
-
{ "cmd": "zcat ${data:TTL_DIR}/core.ttl.gz", "graph": "http://purl.uniprot.org/core" }
|
|
57
|
-
{ "cmd": "zcat ${data:TTL_DIR}/void.ttl.gz", "graph": "http://rdfs.org/ns/void" }]
|
|
56
|
+
{ "cmd": "zcat ${data:TTL_DIR}/core.ttl.gz", "graph": "http://purl.uniprot.org/core" }]
|
|
58
57
|
SETTINGS_JSON = { "languages-internal": [], "prefixes-external": [""], "locale": { "language": "en", "country": "US", "ignore-punctuation": true }, "ascii-prefixes-only": true, "num-triples-per-batch": 25000000 }
|
|
59
58
|
STXXL_MEMORY = 60G
|
|
60
59
|
|
qlever/__init__.py
CHANGED
|
@@ -13,8 +13,11 @@ def snake_to_camel(str):
|
|
|
13
13
|
# Each module in `qlever/commands` corresponds to a command. The name
|
|
14
14
|
# of the command is the base name of the module file.
|
|
15
15
|
package_path = Path(__file__).parent
|
|
16
|
-
command_names = [
|
|
17
|
-
|
|
16
|
+
command_names = [
|
|
17
|
+
Path(p).stem
|
|
18
|
+
for p in package_path.glob("commands/*.py")
|
|
19
|
+
if p.name != "__init__.py"
|
|
20
|
+
]
|
|
18
21
|
|
|
19
22
|
# Dynamically load all the command classes and create an object for each.
|
|
20
23
|
command_objects = {}
|
|
@@ -24,8 +27,10 @@ for command_name in command_names:
|
|
|
24
27
|
try:
|
|
25
28
|
module = __import__(module_path, fromlist=[class_name])
|
|
26
29
|
except ImportError as e:
|
|
27
|
-
raise Exception(
|
|
28
|
-
|
|
30
|
+
raise Exception(
|
|
31
|
+
f"Could not import class {class_name} from module "
|
|
32
|
+
f"{module_path} for command {command_name}: {e}"
|
|
33
|
+
)
|
|
29
34
|
# Create an object of the class and store it in the dictionary. For the
|
|
30
35
|
# commands, take - instead of _.
|
|
31
36
|
command_class = getattr(module, class_name)
|
qlever/command.py
CHANGED
|
@@ -33,7 +33,6 @@ class QleverCommand(ABC):
|
|
|
33
33
|
|
|
34
34
|
@abstractmethod
|
|
35
35
|
def should_have_qleverfile(self) -> bool:
|
|
36
|
-
|
|
37
36
|
"""
|
|
38
37
|
Return `True` if the command should have a Qleverfile, `False`
|
|
39
38
|
otherwise. If a command should have a Qleverfile, but none is
|
|
@@ -43,7 +42,7 @@ class QleverCommand(ABC):
|
|
|
43
42
|
pass
|
|
44
43
|
|
|
45
44
|
@abstractmethod
|
|
46
|
-
def relevant_qleverfile_arguments(self) -> dict[str: list[str]]:
|
|
45
|
+
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
47
46
|
"""
|
|
48
47
|
Retun the arguments relevant for this command. This must be a subset of
|
|
49
48
|
the names of `all_arguments` defined in `QleverConfig`. Only these
|
|
@@ -81,6 +80,8 @@ class QleverCommand(ABC):
|
|
|
81
80
|
log.info(colored(command_description, "blue"))
|
|
82
81
|
log.info("")
|
|
83
82
|
if only_show:
|
|
84
|
-
log.info(
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
log.info(
|
|
84
|
+
'You called "qlever ... --show", therefore the command '
|
|
85
|
+
'is only shown, but not executed (omit the "--show" to '
|
|
86
|
+
"execute it)"
|
|
87
|
+
)
|
|
@@ -17,22 +17,29 @@ class AddTextIndexCommand(QleverCommand):
|
|
|
17
17
|
pass
|
|
18
18
|
|
|
19
19
|
def description(self) -> str:
|
|
20
|
-
return
|
|
20
|
+
return "Add text index to an index built with `qlever index`"
|
|
21
21
|
|
|
22
22
|
def should_have_qleverfile(self) -> bool:
|
|
23
23
|
return True
|
|
24
24
|
|
|
25
|
-
def relevant_qleverfile_arguments(self) -> dict[str: list[str]]:
|
|
26
|
-
return {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
25
|
+
def relevant_qleverfile_arguments(self) -> dict[str : list[str]]:
|
|
26
|
+
return {
|
|
27
|
+
"data": ["name"],
|
|
28
|
+
"index": [
|
|
29
|
+
"index_binary",
|
|
30
|
+
"text_index",
|
|
31
|
+
"text_words_file",
|
|
32
|
+
"text_docs_file",
|
|
33
|
+
],
|
|
34
|
+
"runtime": ["system", "image", "index_container"],
|
|
35
|
+
}
|
|
30
36
|
|
|
31
37
|
def additional_arguments(self, subparser) -> None:
|
|
32
38
|
subparser.add_argument(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
"--overwrite-existing",
|
|
40
|
+
action="store_true",
|
|
41
|
+
help="Overwrite existing text index files",
|
|
42
|
+
)
|
|
36
43
|
|
|
37
44
|
def execute(self, args) -> bool:
|
|
38
45
|
# Check that there is actually something to add.
|
|
@@ -42,24 +49,31 @@ class AddTextIndexCommand(QleverCommand):
|
|
|
42
49
|
|
|
43
50
|
# Construct the command line.
|
|
44
51
|
add_text_index_cmd = f"{args.index_binary} -A -i {args.name}"
|
|
45
|
-
if args.text_index in
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
if args.text_index in [
|
|
53
|
+
"from_text_records",
|
|
54
|
+
"from_text_records_and_literals",
|
|
55
|
+
]:
|
|
56
|
+
add_text_index_cmd += (
|
|
57
|
+
f" -w {args.text_words_file}" f" -d {args.text_docs_file}"
|
|
58
|
+
)
|
|
59
|
+
if args.text_index in [
|
|
60
|
+
"from_literals",
|
|
61
|
+
"from_text_records_and_literals",
|
|
62
|
+
]:
|
|
51
63
|
add_text_index_cmd += " --text-words-from-literals"
|
|
52
64
|
add_text_index_cmd += f" | tee {args.name}.text-index-log.txt"
|
|
53
65
|
|
|
54
66
|
# Run the command in a container (if so desired).
|
|
55
67
|
if args.system in Containerize.supported_systems():
|
|
56
68
|
add_text_index_cmd = Containerize().containerize_command(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
add_text_index_cmd,
|
|
70
|
+
args.system,
|
|
71
|
+
"run --rm",
|
|
72
|
+
args.image,
|
|
73
|
+
args.index_container,
|
|
74
|
+
volumes=[("$(pwd)", "/index")],
|
|
75
|
+
working_directory="/index",
|
|
76
|
+
)
|
|
63
77
|
|
|
64
78
|
# Show the command line.
|
|
65
79
|
self.show(add_text_index_cmd, only_show=args.show)
|
|
@@ -71,17 +85,22 @@ class AddTextIndexCommand(QleverCommand):
|
|
|
71
85
|
try:
|
|
72
86
|
run_command(f"{args.index_binary} --help")
|
|
73
87
|
except Exception as e:
|
|
74
|
-
log.error(
|
|
75
|
-
|
|
76
|
-
|
|
88
|
+
log.error(
|
|
89
|
+
f'Running "{args.index_binary}" failed ({e}), '
|
|
90
|
+
f"set `--index-binary` to a different binary or "
|
|
91
|
+
f"use `--container_system`"
|
|
92
|
+
)
|
|
77
93
|
return False
|
|
78
94
|
|
|
79
95
|
# Check if text index files already exist.
|
|
80
96
|
existing_text_index_files = get_existing_index_files(
|
|
81
|
-
|
|
97
|
+
f"{args.name}.text.*"
|
|
98
|
+
)
|
|
82
99
|
if len(existing_text_index_files) > 0 and not args.overwrite_existing:
|
|
83
|
-
log.error(
|
|
84
|
-
|
|
100
|
+
log.error(
|
|
101
|
+
"Text index files found, if you want to overwrite them, "
|
|
102
|
+
"use --overwrite-existing"
|
|
103
|
+
)
|
|
85
104
|
log.info("")
|
|
86
105
|
log.info(f"Index files found: {existing_text_index_files}")
|
|
87
106
|
return False
|
|
@@ -90,7 +109,7 @@ class AddTextIndexCommand(QleverCommand):
|
|
|
90
109
|
try:
|
|
91
110
|
subprocess.run(add_text_index_cmd, shell=True, check=True)
|
|
92
111
|
except Exception as e:
|
|
93
|
-
log.error(f
|
|
112
|
+
log.error(f'Running "{add_text_index_cmd}" failed ({e})')
|
|
94
113
|
return False
|
|
95
114
|
|
|
96
115
|
return True
|