m_wikiconcept
Look up imported Wikidata/OpenAlex concepts, search their names and connect
them to keyword resources. Concept rows are binary-keyed maps, with properties
from props_json merged into the result. Imported text is not guaranteed to
be safe HTML; escape it when displayed.
Read paths
Path under m.wikiconcept | Result |
|---|---|
id[identifier] | One concept by Wikidata Q-code, OpenAlex C-code or stored HTTPS URL. |
find[identifier] | Alias for id; this is not a free-text search. |
find_keyword[identifier] | Best matching connected keyword resource ID. |
connected[resource_id] | List of concepts connected to a resource. |
list_all | Concepts ordered by local numeric ID, using request arguments page and pagelen (defaults 1 and 50). |
total | Number of imported concepts. |
For example:
{% for concept in m.wikiconcept.connected[id] %}
{{ concept.display_name|escape }}
{% endfor %}
Identifiers accept Q/C prefixes in either case, or an exact stored Wikidata,
OpenAlex or Wikipedia HTTPS URL. A local numeric concept ID is not accepted
by get_concept/2. Successful model reads return {ok, {Value, Rest}};
unknown identifiers return {error, enoent}. Unsupported model paths have
no catch-all clause. Read paths do not check resource visibility or module
permissions, including when returning connected keyword IDs.
find_keyword/2 first uses the concept's own keyword, then the connected
ancestor with the greatest level, then a connected descendant with the
smallest level. It returns {ok, ResourceId} or {error, enoent}.
Write paths
POST to these model paths with a binary-keyed payload map:
| Path | Payload | Behavior |
|---|---|---|
insert/keyword | wikidata | Return or create a keyword for the concept, returning {ok, ResourceId}. |
connect | wikidata, id | Connect the concept to the keyword resource, replacing a previous connection. |
disconnect | wikidata, id | Disconnect the concept from the keyword resource. |
For example, the HTTP model endpoint for connecting is
/api/model/wikiconcept/post/connect, with a JSON body such as
{"wikidata":"Q420","id":1234}. The transport's authentication and topic
ACLs apply independently of the model checks.
Connect/disconnect require z_acl:rsc_editable/2 and a resource in the keyword
category; failures return eacces or enoent. Their direct Erlang helpers do
not repeat these ACL checks. Keyword insertion returns an existing connection
or matching resource URI when available; otherwise it calls m_rsc:insert/2,
trying the system content group and then the default group on eacces.
Reusing a matching resource URI requires an editable keyword resource.
insert_keyword/3 accepts a category within the keyword subtree;
insert_keyword/2 defaults to keyword. Resource insertion checks the selected
category and content group permissions. An already connected keyword is returned unchanged.
For direct Erlang calls with a selected keyword subcategory:
m_wikiconcept:insert_keyword(<<"Q420">>, CategoryId, Context).
The model POST path uses the default keyword category; category selection is
available through insert_keyword/3 and the admin concept dialog.
New keywords are published and use the concept's translated title and summary.
Each field retains nonempty translations matching the site's editable languages.
If none match, a nonempty English translation is copied to
z_language:default_language/1, independently of the current request language.
For titles, missing English text falls back to display_name, then the supplied
concept identifier. The resource's language property follows the resulting title
translations. A summary without a matching or English translation is omitted.
Local search and remote import
m_wikiconcept:find(<<"biology">>, 1, 20, Context).
m_wikiconcept:get_concept(<<"Q420">>, Context).
find/2 defaults to offset 1 and limit 20. find/4 uses a one-based offset,
normalizes text and matches words against local names, using PostgreSQL
trigram similarity for scoring. Empty search text lists concepts by display
name. Results are {ok, [ConceptMap]} or an error. count/2 returns the exact
number of matching concepts using the same criteria, without pagination.
find_descendant/2 defaults to offset 1 and limit 1000; /4 accepts explicit
pagination. It finds descendants one level below the first matching concept.
list_all_concepts/3 instead accepts a one-based page number and page size.
fetch_all/1,2 fetch OpenAlex pages and return
{ok, {Concepts, done | {next, Cursor}}} or an error. load/1 downloads and
stores the complete catalogue. Remote fetch/2, openalex_search/3 and
openalex_autocomplete/3 return provider response data through z_fetch;
they are separate from the local model lookup paths.
Installation and migration preserve existing rows and keyword links.
install_data/1 queues an import only for an empty catalogue; use the admin
Reimport action to refresh populated tables. Imports update records by their
Wikidata URL and reconcile search names while retaining keyword connections.