]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/support-scripts/symspell-sideload.pl
LP1615805 No inputs after submit in patron search (AngularJS)
[Evergreen.git] / Open-ILS / src / support-scripts / symspell-sideload.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use List::MoreUtils qw/uniq/;
5
6 $| = 1;
7
8 my $plen = 6;
9 my $maxed = 3;
10
11 my %dict;
12 my $etime;
13 my $secs;
14
15 my $class = $ARGV[0];
16
17 my $stime = time;
18 while (my $data = <>) {
19     my $line = $.;
20
21     chomp($data); $data=lc($data);
22
23     my @words;
24     while( $data =~ m/([\w\d]+'*[\w\d]*)/g ) {
25         push @words, $1;
26     }
27
28     for my $raw (uniq @words) {
29         my $key = $raw;
30         my $rlen = length($raw);
31         next if ($raw =~ /\d{5,}/ and $rlen > 4);
32
33         $dict{$key} //= [0,[]];
34         $dict{$key}[0]++;
35
36         if ($dict{$key}[0] == 1) { # first time we've seen it, need to generate prefix keys
37             push @{$dict{$key}[1]}, $raw;
38
39             if ($rlen > $plen) {
40                 $key = substr($raw,0,$plen);
41                 $dict{$key} //= [0,[]];
42                 push @{$dict{$key}[1]}, $raw;
43             }
44
45             for my $edit (symspell_generate_edits($key, 1)) {
46                 next unless length($edit);
47                 next if (length($edit) <= ($plen - $maxed) and $rlen > $plen);
48                 $dict{$edit} //= [0,[]];
49                 push @{$dict{$edit}[1]}, $raw;
50             }
51         }
52     }
53
54     unless ($line % 10000) {
55         $etime = time;
56         $secs = $etime - $stime;
57         warn "$line lines consumed from input in $secs seconds...\n";
58     }
59 }
60
61 $etime = time;
62 $secs = $etime - $stime;
63 warn "Dictionary built in $secs seconds, writing...\n";
64
65 $stime = time;
66 my $counter = 0;
67
68 print <<"SQL";
69 CREATE UNLOGGED TABLE search.symspell_dictionary_partial_$class (
70     prefix_key TEXT,
71     ${class}_count INT,
72     ${class}_suggestions TEXT[]
73 );
74
75 COPY search.symspell_dictionary_partial_$class FROM STDIN;
76 SQL
77
78 while ( my ($key, $cl_dict) = each %dict ) {
79     $counter++;
80     print join( "\t", $key, $$cl_dict[0], (scalar(@{$$cl_dict[1]}) ? '{'.join(',', uniq @{$$cl_dict[1]}).'}' : '\N')) . "\n";
81     delete $dict{$key};
82 }
83
84 print <<"SQL";
85 \\.
86
87 INSERT INTO search.symspell_dictionary (prefix_key, ${class}_count, ${class}_suggestions)
88     SELECT * FROM search.symspell_dictionary_partial_$class
89     ON CONFLICT (prefix_key) DO UPDATE
90         SET ${class}_count = EXCLUDED.${class}_count,
91         ${class}_suggestions = EXCLUDED.${class}_suggestions;
92
93 SQL
94
95 $etime = time;
96 $secs = $etime - $stime;
97 warn "$counter dictionary prefix key entries written in $secs seconds.\n";
98
99 sub symspell_generate_edits {
100     my $word = shift;
101     my $dist = shift;
102     my $c = 1;
103     my @list;
104     my @sublist;
105     my $len = length($word);
106
107     while ( $c <= $len ) {
108         my $item = substr($word, 0, $c - 1) . substr($word, $c);
109         push @list, $item;
110         if ($dist < $maxed) {
111             push @sublist, symspell_generate_edits($item, $dist + 1);
112         }
113         $c++;
114     }
115
116     push @list, @sublist;
117
118     if ($dist == 1) {
119             #warn join(', ', uniq @list) . "\n";
120         return uniq(@list);
121     }
122
123     return @list;
124 }
125