Skip to content

Commit 2d699a3

Browse files
authored
Merge pull request #180 from NCEAS/feature-178-project-fts
Project full text search
2 parents 2b993c5 + 66ba140 commit 2d699a3

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* -----------------------------
2+
Project Full Text Search
3+
----------------------------- */
4+
5+
-- Add name/description search column (and index) to project table
6+
ALTER TABLE project
7+
ADD COLUMN search_vector tsvector;
8+
9+
CREATE INDEX idx_project_search
10+
ON project USING gin(search_vector);
11+
12+
-- Create function to construct project search vector for a given project
13+
CREATE OR REPLACE FUNCTION build_project_search_vector(p_project_id INTEGER)
14+
RETURNS tsvector AS $$
15+
DECLARE
16+
result tsvector;
17+
BEGIN
18+
SELECT
19+
setweight(to_tsvector('simple', COALESCE(pj.projectname, '')), 'A') ||
20+
setweight(to_tsvector('simple', COALESCE(pj.projectdescription, '')), 'B')
21+
INTO result
22+
FROM project pj
23+
WHERE pj.project_id = p_project_id;
24+
25+
RETURN result;
26+
END;
27+
$$ LANGUAGE plpgsql STABLE;
28+
29+
-- Create function to populate the project search column with a
30+
-- constructed search vector for a single project record
31+
CREATE OR REPLACE FUNCTION update_project_search_vector(p_project_id INTEGER)
32+
RETURNS void AS $$
33+
BEGIN
34+
UPDATE project
35+
SET search_vector = build_project_search_vector(p_project_id)
36+
WHERE project_id = p_project_id;
37+
END;
38+
$$ LANGUAGE plpgsql;
39+
40+
-- Trigger for any changes to the project record itself
41+
CREATE OR REPLACE FUNCTION project_search_trigger()
42+
RETURNS trigger AS $$
43+
BEGIN
44+
PERFORM update_project_search_vector(NEW.project_id);
45+
RETURN NEW;
46+
END;
47+
$$ LANGUAGE plpgsql;
48+
49+
CREATE TRIGGER trg_project_search
50+
AFTER INSERT OR UPDATE OF projectname, projectdescription ON project
51+
FOR EACH ROW
52+
EXECUTE FUNCTION project_search_trigger();
53+
54+
-- Populate search vectors for all current projects
55+
UPDATE project
56+
SET search_vector = build_project_search_vector(project_id);

vegbank/operators/Project.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def __init__(self, params):
2929

3030
def configure_query(self, *args, **kwargs):
3131
base_columns = {'*': "*"}
32+
base_columns_search = {
33+
'search_rank': "TS_RANK(pj.search_vector, " +
34+
"WEBSEARCH_TO_TSQUERY('simple', %s))"
35+
}
3236
main_columns = {}
3337
main_columns['full'] = {
3438
'pj_code': "'pj.' || project_id",
@@ -53,6 +57,10 @@ def configure_query(self, *args, **kwargs):
5357
'columns': base_columns,
5458
'params': []
5559
},
60+
'search': {
61+
'columns': base_columns_search,
62+
'params': ['search']
63+
},
5664
},
5765
'from': {
5866
'sql': "FROM project AS pj",
@@ -63,6 +71,12 @@ def configure_query(self, *args, **kwargs):
6371
'sql': None,
6472
'params': []
6573
},
74+
'search': {
75+
'sql': """\
76+
pj.search_vector @@ WEBSEARCH_TO_TSQUERY('simple', %s)
77+
""",
78+
'params': ['search']
79+
},
6680
"pj": {
6781
'sql': "pj.project_id = %s",
6882
'params': ['vb_id']
@@ -78,6 +92,10 @@ def configure_query(self, *args, **kwargs):
7892
'columns': main_columns[self.detail],
7993
'params': []
8094
},
95+
'search': {
96+
'columns': {'search_rank': 'pj.search_rank'},
97+
'params': []
98+
},
8199
}
82100
self.query['from'] = {
83101
'sql': from_sql,
@@ -106,8 +124,13 @@ def validate_query_params(self, request_args):
106124
if request_args.get("detail", self.default_detail) not in ("full"):
107125
raise QueryParameterError("When provided, 'detail' must be 'full'.")
108126

109-
# now dispatch to the base validation method
110-
return super().validate_query_params(request_args)
127+
# dispatch to the base validation method
128+
params = super().validate_query_params(request_args)
129+
130+
# capture search parameter, if it exists
131+
params['search'] = request_args.get('search')
132+
133+
return params
111134

112135

113136
def upload_project(self, request, params):

vegbank/vegbankapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ def projects(pj_code):
446446
retrieved. If None, retrieves all projects.
447447
448448
GET Query Parameters:
449+
search (str, optional): Project name search query.
449450
detail (str, optional): Level of detail for the response.
450451
Only 'full' is defined for this method. Defaults to 'full'.
451452
limit (int, optional): Maximum number of records to return.

0 commit comments

Comments
 (0)