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.

@@ -1,33 +1,36 @@
1
- # Qleverfile for OHM Planet, use with https://github.com/ad-freiburg/qlever-control
1
+ # Qleverfile for OpenHistoricalMap, use with the QLever CLI (`pip install qlever`)
2
2
  #
3
- # qlever get-data # ~20 mins (download PBF, convert to TTL, add GeoSPARQL triples)
4
- # qlever index # ~20 mins and ~5 GB RAM (on an AMD Ryzen 9 5900X)
5
- # qlever start # ~1 sec
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
- # For `qlever get-data` to work, `osm2rdf` must be installed and in the `PATH`.
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 = curl -LRfC - -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 --cache . --add-hascentroid 2>&1 | tee ${NAME}.osm2rdf-log.txt
15
- GET_DATA_CMD = set -o pipefail && ${CHECK_BINARIES} && ${GET_DATA_CMD_1} && echo && ${GET_DATA_CMD_2}
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 = ${data:NAME}.ttl.bz2
21
- CAT_INPUT_FILES = bzcat -f ${INPUT_FILES}
22
- SETTINGS_JSON = { "prefixes-external": [""], "ascii-prefixes-only": false, "parallel-parsing": true, "num-triples-per-batch": 5000000 }
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/mapui-petri/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
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 qlever script (pip install qlever)
1
+ # Qleverfile for OSM Planet, use with the QLever CLI (`pip install qlever`)
2
2
  #
3
- # qlever get-data # takes ~50 mins to download .ttl.bz2 file of ~ 300 GB
4
- # qlever index # takes ~12 hours and ~20 GB RAM (on an AMD Ryzen 9 5900X)
5
- # qlever start # takes a few seconds
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
- # For the OSM data of a single country, do `qlever setup-config osm-country`
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 = curl --location --fail --continue-at - --remote-time --output ${NAME}.ttl.bz2 ${DATA_URL}
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 = ${data:NAME}.ttl.bz2
19
- CAT_INPUT_FILES = lbzcat -f -n 2 ${INPUT_FILES}
20
- STXXL_MEMORY = 20G
21
- SETTINGS_JSON = { "languages-internal": [], "prefixes-external": [""], "ascii-prefixes-only": false, "num-triples-per-batch": 5000000 }
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 = 90G
27
- CACHE_MAX_SIZE = 40G
28
- CACHE_MAX_SIZE_SINGLE_ENTRY = 30G
29
- TIMEOUT = 300s
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 = [Path(p).stem for p in package_path.glob("commands/*.py")
17
- if p.name != "__init__.py"]
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(f"Could not import class {class_name} from module "
28
- f"{module_path} for command {command_name}: {e}")
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("You called \"qlever ... --show\", therefore the command "
85
- "is only shown, but not executed (omit the \"--show\" to "
86
- "execute it)")
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 ("Add text index to an index built with `qlever index`")
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 {"data": ["name"],
27
- "index": ["index_binary", "text_index",
28
- "text_words_file", "text_docs_file"],
29
- "runtime": ["system", "image", "index_container"]}
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
- "--overwrite-existing",
34
- action="store_true",
35
- help="Overwrite existing text index files")
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
- ["from_text_records", "from_text_records_and_literals"]:
47
- add_text_index_cmd += (f" -w {args.text_words_file}"
48
- f" -d {args.text_docs_file}")
49
- if args.text_index in \
50
- ["from_literals", "from_text_records_and_literals"]:
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
- add_text_index_cmd,
58
- args.system, "run --rm",
59
- args.image,
60
- args.index_container,
61
- volumes=[("$(pwd)", "/index")],
62
- working_directory="/index")
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(f"Running \"{args.index_binary}\" failed ({e}), "
75
- f"set `--index-binary` to a different binary or "
76
- f"use `--container_system`")
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
- f"{args.name}.text.*")
97
+ f"{args.name}.text.*"
98
+ )
82
99
  if len(existing_text_index_files) > 0 and not args.overwrite_existing:
83
- log.error("Text index files found, if you want to overwrite them, "
84
- "use --overwrite-existing")
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"Running \"{add_text_index_cmd}\" failed ({e})")
112
+ log.error(f'Running "{add_text_index_cmd}" failed ({e})')
94
113
  return False
95
114
 
96
115
  return True