Skip to content

Commit

Permalink
[Fixes #11097] Faceting: resource type
Browse files Browse the repository at this point in the history
  • Loading branch information
etj committed Jul 6, 2023
1 parent 543d751 commit f839d39
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 22 deletions.
2 changes: 1 addition & 1 deletion geonode/facets/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
FACET_TYPE_USER = "user"
FACET_TYPE_THESAURUS = "thesaurus"
FACET_TYPE_CATEGORY = "category"
FACET_TYPE_RESOURCETYPE = "resourcetype"
FACET_TYPE_BASE = "base"

logger = logging.getLogger(__name__)

Expand Down
147 changes: 147 additions & 0 deletions geonode/facets/providers/baseinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#########################################################################
#
# Copyright (C) 2023 Open Source Geospatial Foundation - all rights reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#########################################################################

import logging

from django.db.models import Count

from geonode.facets.models import FacetProvider, DEFAULT_FACET_PAGE_SIZE, FACET_TYPE_BASE

logger = logging.getLogger(__name__)


class ResourceTypeFacetProvider(FacetProvider):
"""
Implements faceting for resources' type and subtype
"""

@property
def name(self) -> str:
return "resourcetype"

def get_info(self, lang="en") -> dict:
return {
"name": self.name,
"key": "filter{resource_type.in}",
"label": "Resource type",
"type": FACET_TYPE_BASE,
"hierarchical": True,
"order": 0,
}

def get_facet_items(
self,
queryset=None,
start: int = 0,
end: int = DEFAULT_FACET_PAGE_SIZE,
lang="en",
topic_contains: str = None,
) -> (int, list):
logger.debug("Retrieving facets for %s", self.name)

if topic_contains:
logger.warning(f"Facet {self.name} does not support topic_contains filtering")

q = queryset.values("resource_type", "subtype")
q = q.annotate(ctype=Count("resource_type"), csub=Count("subtype"))
q = q.order_by()

# aggregate subtypes into rtypes
tree = {}
for r in q.all():
res_type = r["resource_type"]
t = tree.get(res_type, {"cnt": 0, "sub": {}})
t["cnt"] += r["ctype"]
if sub := r["subtype"]:
t["sub"][sub] = {"cnt": r["ctype"]}
tree[res_type] = t

logger.info("Found %d main facets for %s", len(tree), self.name)
logger.debug(" ---> %s\n\n", q.query)
logger.debug(" ---> %r\n\n", q.all())

topics = []
for rtype, info in tree.items():
t = {"key": rtype, "label": rtype, "count": info["cnt"]}
if sub := info["sub"]:
children = []
for stype, sinfo in sub.items():
children.append({"key": stype, "label": stype, "count": sinfo["cnt"]})
t["filter"] = "filter{subtype.in}"
t["items"] = sorted(children, reverse=True, key=lambda x: x["count"])
topics.append(t)

return len(topics), sorted(topics, reverse=True, key=lambda x: x["count"])

@classmethod
def register(cls, registry, **kwargs) -> None:
registry.register_facet_provider(ResourceTypeFacetProvider())


class FeaturedFacetProvider(FacetProvider):
"""
Implements faceting for resources flagged as featured
"""

@property
def name(self) -> str:
return "featured"

def get_info(self, lang="en") -> dict:
return {
"name": self.name,
"key": "filter{featured}",
"label": "Featured",
"type": FACET_TYPE_BASE,
"hierarchical": False,
"order": 0,
}

def get_facet_items(
self,
queryset=None,
start: int = 0,
end: int = DEFAULT_FACET_PAGE_SIZE,
lang="en",
topic_contains: str = None,
) -> (int, list):
logger.debug("Retrieving facets for %s", self.name)

if topic_contains:
logger.warning(f"Facet {self.name} does not support topic_contains filtering")

q = queryset.values("featured").annotate(cnt=Count("featured")).order_by()

logger.debug(" ---> %s\n\n", q.query)
logger.debug(" ---> %r\n\n", q.all())

topics = [
{
"key": r["featured"],
"label": str(r["featured"]),
"count": r["cnt"],
}
for r in q[start:end]
]

return 2, topics

@classmethod
def register(cls, registry, **kwargs) -> None:
registry.register_facet_provider(FeaturedFacetProvider())
60 changes: 39 additions & 21 deletions geonode/facets/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,49 +114,46 @@ def _create_resources(self):

# These are the assigned keywords to the Resources

# RB00 -> T1K0 R0,R1
# RB01 -> T0K0 T1K0 R0
# RB02 -> T1K0 R1
# RB00 -> T1K0 R0,R1 FEAT
# RB01 -> T0K0 T1K0 R0 FEAT
# RB02 -> T1K0 R1 FEAT
# RB03 -> T0K0 T1K0
# RB04 -> T1K0
# RB05 -> T0K0 T1K0
# RB06 -> T1K0
# RB07 -> T0K0 T1K0
# RB08 -> T1K0 T1K1 R1
# RB06 -> T1K0 FEAT
# RB07 -> T0K0 T1K0 FEAT
# RB08 -> T1K0 T1K1 R1 FEAT
# RB09 -> T0K0 T1K0 T1K1
# RB10 -> T1K1
# RB11 -> T0K0 T0K1 T1K1
# RB12 -> T1K1
# RB13 -> T0K0 T0K1 R1
# RB14 ->
# RB12 -> T1K1 FEAT
# RB13 -> T0K0 T0K1 R1 FEAT
# RB14 -> FEAT
# RB15 -> T0K0 T0K1
# RB16 ->
# RB17 -> T0K0 T0K1
# RB18 ->
# RB19 -> T0K0 T0K1
# RB18 -> FEAT
# RB19 -> T0K0 T0K1 FEAT

if x % 2 == 1:
print(f"ADDING KEYWORDS {self.thesauri_k['0_0']} to RB {d}")
d.tkeywords.add(self.thesauri_k["0_0"])
d.save()
if x % 2 == 1 and x > 10:
print(f"ADDING KEYWORDS {self.thesauri_k['0_1']} to RB {d}")
d.tkeywords.add(self.thesauri_k["0_1"])
d.save()
if x < 10:
print(f"ADDING KEYWORDS {self.thesauri_k['1_0']} to RB {d}")
d.tkeywords.add(self.thesauri_k["1_0"])
d.save()
if 7 < x < 13:
d.tkeywords.add(self.thesauri_k["1_1"])
d.save()
if x in (0, 1):
d.regions.add(self.regions["R0"])
d.save()
if x in (0, 2, 8, 13):
d.regions.add(self.regions["R1"])
d.save()
if (x % 6) in (0, 1, 2):
d.featured = True

d.save()
d.set_permissions(public_perm_spec)

@staticmethod
Expand All @@ -169,9 +166,9 @@ def test_facets_base(self):
obj = json.loads(res.content)
self.assertIn("facets", obj)
facets_list = obj["facets"]
self.assertEqual(5, len(facets_list))
self.assertEqual(7, len(facets_list))
fmap = self._facets_to_map(facets_list)
for name in ("category", "owner", "t_0", "t_1"):
for name in ("category", "owner", "t_0", "t_1", "featured", "resourcetype"):
self.assertIn(name, fmap)

def test_facets_rich(self):
Expand All @@ -189,7 +186,7 @@ def test_facets_rich(self):
obj = json.loads(res.content)

facets_list = obj["facets"]
self.assertEqual(5, len(facets_list))
self.assertEqual(7, len(facets_list))
fmap = self._facets_to_map(facets_list)
for expected in (
{
Expand Down Expand Up @@ -233,6 +230,25 @@ def test_facets_rich(self):
],
},
},
{
"name": "featured",
"topics": {
"total": 2,
"items": [
{"label": "True", "key": True, "count": 11},
{"label": "False", "key": False, "count": 9},
],
},
},
{
"name": "resourcetype",
"topics": {
"total": 1,
"items": [
{"label": "resourcebase", "key": "resourcebase", "count": 20},
],
},
},
):
name = expected["name"]
self.assertIn(name, fmap)
Expand All @@ -254,7 +270,9 @@ def test_facets_rich(self):
found = item
break

self.assertIsNotNone(item, f"topic not found '{exp_label}'")
self.assertIsNotNone(
found, f"topic not found '{exp_label}' for facet '{name}' -- found items {items}"
)
for exp_field in exp_item:
self.assertEqual(
exp_item[exp_field], found[exp_field], f"Mismatch item key:{exp_field} facet:{name}"
Expand Down
2 changes: 2 additions & 0 deletions geonode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,8 @@ def get_geonode_catalogue_service():
GEONODE_APPS += ("geonode.facets",)

FACET_PROVIDERS = (
"geonode.facets.providers.baseinfo.ResourceTypeFacetProvider",
"geonode.facets.providers.baseinfo.FeaturedFacetProvider",
"geonode.facets.providers.category.CategoryFacetProvider",
"geonode.facets.providers.users.OwnerFacetProvider",
"geonode.facets.providers.thesaurus.ThesaurusFacetProvider",
Expand Down

0 comments on commit f839d39

Please sign in to comment.