]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/support-scripts/symspell-sideload.pl
257f28b05ccb019a8c368bc7518fb96ade8d8bd3
[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         $dict{$key} //= [0,[]];
31         $dict{$key}[0]++;
32
33         if ($dict{$key}[0] == 1) { # first time we've seen it, need to generate prefix keys
34             push @{$dict{$key}[1]}, $raw;
35
36             if (length($raw) > $plen) {
37                 $key = substr($raw,0,$plen);
38                 $dict{$key} //= [0,[]];
39                 push @{$dict{$key}[1]}, $raw;
40             }
41
42             for my $edit (symspell_generate_edits($key, 1)) {
43                 $dict{$edit} //= [0,[]];
44                 push @{$dict{$edit}[1]}, $raw;
45             }
46         }
47     }
48
49     unless ($line % 10000) {
50         $etime = time;
51         $secs = $etime - $stime;
52         warn "$line lines consumed from input in $secs seconds...\n";
53     }
54 }
55
56 $etime = time;
57 $secs = $etime - $stime;
58 warn "Dictionary built in $secs seconds, writing...\n";
59
60 $stime = time;
61 my $counter = 0;
62
63 print <<"SQL";
64 CREATE UNLOGGED TABLE search.symspell_dictionary_partial_$class (
65     prefix_key TEXT,
66     ${class}_count INT,
67     ${class}_suggestions TEXT[]
68 );
69
70 COPY search.symspell_dictionary_partial_$class FROM STDIN;
71 SQL
72
73 while ( my ($key, $cl_dict) = each %dict ) {
74     $counter++;
75     print join( "\t", $key, $$cl_dict[0], (scalar(@{$$cl_dict[1]}) ? '{'.join(',', uniq @{$$cl_dict[1]}).'}' : '\N')) . "\n";
76     delete $dict{$key};
77 }
78
79 print <<"SQL";
80 \\.
81
82 INSERT INTO search.symspell_dictionary (prefix_key, ${class}_count, ${class}_suggestions)
83     SELECT * FROM search.symspell_dictionary_partial_$class
84     ON CONFLICT (prefix_key) DO UPDATE
85         SET ${class}_count = EXCLUDED.${class}_count,
86         ${class}_suggestions = EXCLUDED.${class}_suggestions;
87
88 SQL
89
90 $etime = time;
91 $secs = $etime - $stime;
92 warn "$counter dictionary prefix key entries written in $secs seconds.\n";
93
94 sub symspell_generate_edits {
95     my $word = shift;
96     my $dist = shift;
97     my $c = 1;
98     my @list;
99     my @sublist;
100     my $len = length($word);
101
102     while ( $c <= $len ) {
103         my $item = substr($word, 0, $c - 1) . substr($word, $c);
104         push @list, $item;
105         if ($dist < $maxed) {
106             push @sublist, symspell_generate_edits($item, $dist + 1);
107         }
108         $c++;
109     }
110
111     push @list, @sublist;
112
113     if ($dist == 1) {
114             #warn join(', ', uniq @list) . "\n";
115         return uniq(@list);
116     }
117
118     return @list;
119 }
120