gmnifaq

faq engine for gemini with full text search
git clone https://git.clttr.info/gmnifaq.git
Log (Feed) | Files | Refs (Tags) | README | LICENSE

commit 4516bfc5a39f8ea8632cd1ed240d350454878c33
parent ac99b4092b057be8aeb3237c92a32329d931aa01
Author: René Wagner <rwagner@rw-net.de>
Date:   Tue, 19 Jan 2021 21:35:23 +0100

implement fts for searching

Diffstat:
Mdata/data.sqlite.example | 0
Mfaqs.pl | 16++++++++++++----
Ascripts.sql | 17+++++++++++++++++
Msearch.pl | 12++++++------
Mtags.pl | 2+-
5 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/data/data.sqlite.example b/data/data.sqlite.example Binary files differ. diff --git a/faqs.pl b/faqs.pl @@ -38,11 +38,11 @@ sub sql } if ( $query =~ /tag=([0-9]+)/i ) { - return "SELECT q.* FROM questions q JOIN tags_questions tq ON q.id = tq.q_id WHERE tq.t_id = $1"; + return "SELECT q.* FROM questions q LEFT JOIN tags_questions tq ON q.id = tq.q_id WHERE tq.t_id = $1"; } if ( $query =~ /faq=([0-9]+)/i ) { - return "SELECT q.* FROM questions q JOIN tags_questions tq ON q.id = tq.q_id WHERE q.id = $1"; + return "SELECT q.* FROM questions q LEFT JOIN tags_questions tq ON q.id = tq.q_id WHERE q.id = $1"; } write_response('INTERNAL_SERVER_ERROR', 'CGI execution error', undef); } @@ -53,17 +53,25 @@ sub faqs my $dbh = DBI->connect($CONF{'dsn'}, '', '', { RaiseError => 1 }) or die $DBI::errstr; my @rows = $dbh->selectall_array(sql()); - $dbh->disconnect(); if ( !scalar @rows ) { push @return, 'No faqs found!'; } else { foreach (@rows) { - push @return, sprintf("### %s", @$_[1]); + push @return, sprintf("## %s", @$_[1]); + my @tags = $dbh->selectall_array("SELECT id, name FROM tags t LEFT JOIN tags_questions tq ON tq.t_id = t.id WHERE tq.q_id = @$_[0];"); + + if ( scalar @tags ) { + push @return, ('', 'Tags:'); + foreach (@tags) { + push @return, sprintf("=> ./faqs.pl?tag=%d %s", @$_[0], @$_[1]); + } + } push @return, ('', @$_[2], ''); } } + $dbh->disconnect(); push @return, ''; return @return; } diff --git a/scripts.sql b/scripts.sql @@ -0,0 +1,17 @@ +select DISTINCT tags.*, count(tags_questions.q_id) as count from fts_data inner join tags on tags.id = fts_data.t_id +left join tags_questions on tags_questions.t_id = tags.id +where fts_data match '"text": "gemin"' +ORDER BY rank + +select DISTINCT q_id, questions.question from fts_data inner join questions on questions.id = q_id +where fts_data match '"text": "linux"' +ORDER BY rank; + +-- fill fts_data +INSERT INTO fts_data (q_id, text) SELECT id, question FROM questions; +INSERT INTO fts_data (q_id, text) SELECT id, answer FROM questions; +INSERT INTO fts_data (t_id, text) SELECT id, name FROM tags; + +-- create fts_data table +CREATE VIRTUAL TABLE fts_data +USING FTS5(t_id, q_id, text, tokenize = "porter unicode61") diff --git a/search.pl b/search.pl @@ -22,7 +22,7 @@ if (!defined($ENV{'SERVER_PROTOCOL'}) || $ENV{'SERVER_PROTOCOL'} ne 'GEMINI') { } my $query = lc(uri_unescape($ENV{'QUERY_STRING'})); -if ($query eq '' || $query !~ /^[0-9a-z]*$/i) +if ($query eq '' || $query !~ /^[0-9a-z\s]*$/i) { write_response('INPUT', 'Search faqs for the following terms (separate by blank)', undef); } @@ -42,15 +42,15 @@ sub search my @result = (); my $dbh = DBI->connect($CONF{'dsn'}, '', '', { RaiseError => 1 }) or die $DBI::errstr; - my @matchingtags = $dbh->selectall_array("SELECT id, name, count(t_id) FROM tags LEFT JOIN tags_questions ON tags_questions.t_id = tags.id WHERE name LIKE '%$term%' GROUP BY t_id"); - my @matchingfaqs = $dbh->selectall_array("SELECT * FROM questions WHERE question LIKE '%$term%' OR answer LIKE '%$term%'"); + my @matchingtags = $dbh->selectall_array("SELECT DISTINCT t.*, count(tq.q_id) AS count FROM fts_data INNER JOIN tags t ON t.id = fts_data.t_id LEFT JOIN tags_questions tq ON tq.t_id = t.id WHERE fts_data MATCH '\"text\": \"$term\"' GROUP BY t.id ORDER BY rank"); + my @matchingfaqs = $dbh->selectall_array("SELECT DISTINCT q_id, q.question FROM fts_data INNER JOIN questions q ON q.id = q_id WHERE fts_data MATCH '\"text\": \"$term\"' ORDER BY rank;"); $dbh->disconnect(); - if ( !scalar(@matchingtags) && !scalar(@matchingfaqs)) { + if ( !scalar @matchingtags && !scalar @matchingfaqs) { push @result, ('Sorry, we can\'t find an entry that matches your search data.', ''); } - if ( scalar(@matchingtags)) { + if ( scalar @matchingtags) { push @result, ('## matching tags', ''); foreach (@matchingtags) { push @result, sprintf("=> ./faqs.pl?tag=%d %s (%d entrys)", @$_[0], @$_[1], @$_[2]); @@ -58,7 +58,7 @@ sub search push @result, ''; } - if ( scalar(@matchingfaqs)) { + if ( scalar @matchingfaqs) { push @result, ('## matching FAQs', ''); foreach (@matchingfaqs) { push @result, sprintf("=> ./faqs.pl?faq=%d %s", @$_[0], @$_[1]); diff --git a/tags.pl b/tags.pl @@ -34,7 +34,7 @@ sub tags my $dbh = DBI->connect($CONF{'dsn'}, '', '', { RaiseError => 1 }) or die $DBI::errstr; my @result; - my @rows = $dbh->selectall_array('SELECT id, name, count(t_id) FROM tags LEFT JOIN tags_questions ON tags_questions.t_id = tags.id GROUP BY t_id'); + my @rows = $dbh->selectall_array('SELECT id, name, count(t_id) FROM tags t LEFT JOIN tags_questions tq ON tq.t_id = t.id GROUP BY t_id'); $dbh->disconnect(); if ( !scalar @rows ) {