Skip to content

Commit 8857bce

Browse files
author
Sean Sullivan
committed
Merge branch 'dev' of github.com:spectriclabs/elastic_datashader into dev
2 parents 9787251 + 746ec96 commit 8857bce

File tree

6 files changed

+64
-19
lines changed

6 files changed

+64
-19
lines changed

Dockerfile

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ COPY elastic_datashader /build/elastic_datashader
1111
WORKDIR /build/elastic_datashader
1212
RUN poetry build
1313

14-
FROM python:3.11 AS deployment
14+
FROM python:3.11-slim AS deployment
1515
LABEL maintainer="[email protected]"
1616
RUN useradd -d /home/datashader datashader && \
1717
mkdir -p /home/datashader /opt/elastic_datashader/tms-cache && \
@@ -23,8 +23,8 @@ COPY --from=builder /build/dist/*.whl /home/datashader/tmp/
2323
ENV PATH="$PATH:/home/datashader/.local/bin"
2424
RUN pip install --upgrade pip && \
2525
pip install --no-cache-dir /home/datashader/tmp/*.whl && \
26-
pip install gunicorn==20.1.0 && \
27-
pip install uvicorn==0.22.0
26+
pip install gunicorn==21.2.0 && \
27+
pip install uvicorn==0.24.0
2828

2929
COPY deployment/logging_config.yml /opt/elastic_datashader/
3030
COPY deployment/gunicorn_config.py /opt/elastic_datashader/

elastic_datashader/main.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from asyncio import create_task
22

33
from fastapi import FastAPI
4-
4+
from fastapi.middleware.cors import CORSMiddleware
55
import urllib3
66

77
from .cache import background_cache_cleanup
@@ -30,6 +30,19 @@
3030
app.include_router(legend.router)
3131
app.include_router(tms.router)
3232

33+
34+
35+
36+
origins = ["*"]
37+
38+
app.add_middleware(
39+
CORSMiddleware,
40+
allow_origins=origins,
41+
allow_credentials=True,
42+
allow_methods=["*"],
43+
allow_headers=["*"],
44+
)
45+
3346
@app.on_event("startup")
3447
async def app_startup():
3548
create_task(background_cache_cleanup())

elastic_datashader/parameters.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,29 @@
1212
from elasticsearch import Elasticsearch
1313
from elasticsearch.exceptions import NotFoundError, ConflictError
1414
from elasticsearch_dsl import Document
15+
from pydantic import BaseModel, Field
1516

1617
from .config import config
1718
from .elastic import get_search_base, build_dsl_filter
1819
from .logger import logger
1920
from .timeutil import quantize_time_range, convert_kibana_time
2021

2122

23+
class SearchParams(BaseModel):
24+
geopoint_field: str
25+
params: dict
26+
cmap: str = Field(default="bym")
27+
resolution: str = Field(default="finest")
28+
span_range: str = Field(default="auto", alias='span')
29+
spread: str = Field(default="auto") # Point Size
30+
timeOverlap: bool = Field(default=False)
31+
timeOverlapSize: str = Field(default="auto")
32+
timestamp_field: str = Field(default="@timestamp")
33+
search_nautical_miles: int = Field(default=50)
34+
geofield_type: str = Field(default='geo_point')
35+
bucket_max: float = Field(default=100, ge=0, le=100)
36+
bucket_min: float = Field(default=0, ge=0, le=1)
37+
2238
def create_default_params() -> Dict[str, Any]:
2339
return {
2440
"category_field": None,
@@ -287,7 +303,7 @@ def extract_parameters(headers: Dict[Any, Any], query_params: Dict[Any, Any]) ->
287303
params["highlight"] = query_params.get("highlight")
288304
params["spread"] = normalize_spread(query_params.get("spread"))
289305
params["resolution"] = query_params.get("resolution", params["resolution"])
290-
params["use_centroid"] = query_params.get("use_centroid", default=params["use_centroid"])
306+
params["use_centroid"] = query_params.get("use_centroid", params["use_centroid"])
291307
params["cmap"] = get_cmap(query_params.get("cmap", None), category_field)
292308
params["span_range"] = query_params.get("span", "auto")
293309
params["geopoint_field"] = query_params.get("geopoint_field", params["geopoint_field"])

elastic_datashader/routers/tms.py

+22-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
from typing import Optional
44
import time
55
import uuid
6+
import json
67
from elasticsearch import Elasticsearch
78
from elasticsearch.exceptions import NotFoundError
89
from elasticsearch_dsl import Document
910
from fastapi import APIRouter, BackgroundTasks, HTTPException, Request, Response
10-
from fastapi.responses import RedirectResponse
11+
from fastapi.responses import RedirectResponse, JSONResponse
1112
from starlette.datastructures import URL
1213

1314
from ..cache import (
@@ -26,7 +27,7 @@
2627
from ..drawing import generate_x_tile
2728
from ..elastic import get_es_headers, get_search_base
2829
from ..logger import logger
29-
from ..parameters import extract_parameters, merge_generated_parameters
30+
from ..parameters import extract_parameters, merge_generated_parameters, SearchParams
3031
from ..tilegen import (
3132
TILE_HEIGHT_PX,
3233
TILE_WIDTH_PX,
@@ -148,8 +149,8 @@ def cached_response(es, idx, x, y, z, params, parameter_hash) -> Optional[Respon
148149

149150
try:
150151
es.update( # pylint: disable=E1123
151-
".datashader_tiles",
152-
tile_id(idx, x, y, z, parameter_hash),
152+
index=".datashader_tiles",
153+
id=tile_id(idx, x, y, z, parameter_hash),
153154
body={"script" : {"source": "ctx._source.cache_hits++"}},
154155
retry_on_conflict=5,
155156
)
@@ -281,18 +282,21 @@ def generate_tile_to_cache(idx: str, x: int, y: int, z: int, params, parameter_h
281282
logger.debug("Releasing cache placeholder %s", rendering_tile_name(idx, x, y, z, parameter_hash))
282283
release_cache_placeholder(config.cache_path, rendering_tile_name(idx, x, y, z, parameter_hash))
283284

284-
async def fetch_or_render_tile(already_waited: int, idx: str, x: int, y: int, z: int, request: Request, background_tasks: BackgroundTasks):
285+
async def fetch_or_render_tile(already_waited: int, idx: str, x: int, y: int, z: int, request: Request, background_tasks: BackgroundTasks, post_params=None):
285286
check_proxy_key(request.headers.get('tms-proxy-key'))
286287

287288
es = Elasticsearch(
288289
config.elastic_hosts.split(","),
289290
verify_certs=False,
290291
timeout=120,
291292
)
292-
293+
if post_params is None:
294+
post_params = {}
293295
# Get hash and parameters
294296
try:
295-
parameter_hash, params = extract_parameters(request.headers, request.query_params)
297+
print(request.query_params)
298+
print(post_params)
299+
parameter_hash, params = extract_parameters(request.headers, {**request.query_params, **post_params})
296300
# try to build the dsl object bad filters cause exceptions that are then retried.
297301
# underlying elasticsearch_dsl doesn't support the elasticsearch 8 api yet so this causes requests to thrash
298302
# If the filters are bad or elasticsearch_dsl cannot build the request will never be completed so serve X tile
@@ -344,3 +348,14 @@ async def get_tms(idx: str, x: int, y: int, z: int, request: Request, background
344348
@router.get("/{already_waited}/{idx}/{z}/{x}/{y}.png")
345349
async def get_tms_after_wait(already_waited: int, idx: str, x: int, y: int, z: int, request: Request, background_tasks: BackgroundTasks):
346350
return await fetch_or_render_tile(already_waited, idx, x, y, z, request, background_tasks)
351+
352+
353+
@router.post("/{idx}/{z}/{x}/{y}.png")
354+
async def post_tile(already_waited: int, idx: str, x: int, y: int, z: int, request: Request, params: SearchParams, background_tasks: BackgroundTasks):
355+
params = params.dict()
356+
params["params"] = json.dumps(params["params"])
357+
response = await fetch_or_render_tile(0, idx, x, y, z, request, background_tasks, post_params=params)
358+
if isinstance(response, RedirectResponse):
359+
print(already_waited)
360+
return JSONResponse(status_code=200, content={"retry-after": response.headers['retry-after']})
361+
return response

elastic_datashader/tilegen.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -969,7 +969,7 @@ def generate_tile(idx, x, y, z, headers, params, tile_width_px=256, tile_height_
969969

970970
# Create base search
971971
base_s = get_search_base(config.elastic_hosts, headers, params, idx)
972-
base_s = base_s[0:0]
972+
# base_s = base_s[0:0]
973973
# Now find out how many documents
974974
count_s = copy.copy(base_s)[0:0] # slice of array sets from/size since we are aggregating the data we don't need the hits
975975
count_s = count_s.filter("geo_bounding_box", **{geopoint_field: bb_dict})
@@ -1023,7 +1023,7 @@ def generate_tile(idx, x, y, z, headers, params, tile_width_px=256, tile_height_
10231023
geotile_precision = min(max(current_zoom, current_zoom + agg_zooms), MAXIMUM_PERCISION)
10241024

10251025
tile_s = copy.copy(base_s)
1026-
tile_s = tile_s.params(size=0, track_total_hits=False)
1026+
tile_s = tile_s.params(track_total_hits=False)
10271027
tile_s = tile_s.filter(
10281028
"geo_bounding_box", **{geopoint_field: bb_dict}
10291029
)

pyproject.toml

+6-5
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ elastic_datashader = "elastic_datashader.cli:main"
2121

2222
[tool.poetry.dependencies]
2323
python = ">=3.10,<4"
24-
elasticsearch = "7.17.4"
25-
elasticsearch-dsl = "7.4.0"
26-
datashader = "0.15.2"
24+
elasticsearch = "8.11.1"
25+
elasticsearch-dsl = "8.11.0"
26+
datashader = "0.16.0"
2727
pandas = "^1.5.3"
2828
colorcet = "^3.0.1"
2929
mercantile = "1.2.1"
@@ -32,11 +32,11 @@ Pillow = "*"
3232
pynumeral = "*"
3333
arrow = "*"
3434
python-datemath = "*"
35-
numba = "0.57.0"
35+
numba = "0.57.1"
3636
numpy = "^1.23"
3737
PyYAML = "*"
3838
humanize = "*"
39-
uvicorn = {extras = ["standard"], version = "^0.18.2", optional = true}
39+
uvicorn = {extras = ["standard"], version = "0.24.0", optional = true}
4040
fastapi = "^0.96"
4141
georgio = "2023.156.924"
4242
jinja2 = "3.1.2"
@@ -57,6 +57,7 @@ localwebserver = ["uvicorn"]
5757

5858
[tool.pylint.'MESSAGES CONTROL']
5959
max-line-length = 150
60+
extension-pkg-whitelist = "pydantic"
6061
disable = "too-many-nested-blocks,too-many-branches,too-many-statements,R0801,R0902,R0903,R0911,R0913,R0914,C0103,C0114,C0115,C0116,C0123,C0301,C0302,fixme"
6162

6263
[tool.black]

0 commit comments

Comments
 (0)