blob: f75ca905d1985dbe53f059a3569124a82309c977 [file] [log] [blame]
Marc Kupietzbf9bac02022-04-11 21:16:47 +02001use utf8;
2package IDS::DeReKoVecs::Read;
Marc Kupietz3576c622023-11-05 08:51:58 +01003use LWP::Simple;
Marc Kupietzbf9bac02022-04-11 21:16:47 +02004use strict;
5use warnings;
6use Config;
7
8my $src_file = undef;
9
Marc Kupietzbf9bac02022-04-11 21:16:47 +020010our $opt_p = 5676;
11our $opt_C;
12
Marc Kupietzaf436142026-07-30 14:40:10 +090013# Cached values are large (a classic collocator profile is tens to hundreds of
14# kilobytes of JSON), so the caches are size limited. Without a limit a long
15# running worker accumulates one entry per queried word until the box runs out
16# of memory. Defaults can be overridden via configure_cache().
17our $CC_CACHE_MAX_KEYS = 200; # classic collocators
18our $SP_CACHE_MAX_KEYS = 200; # similar profiles
19
Marc Kupietzbf9bac02022-04-11 21:16:47 +020020BEGIN {
21 $src_file = __FILE__;
22 $src_file =~ s/Read.pm/derekovecs-server.c/;
23}
24
Marc Kupietzf6046912024-12-03 17:21:57 +010025use Inline C => "$src_file" => CLEAN_AFTER_BUILD => 0, BUILD_NOISY => 1, ccflags => $Config{ccflags} . "-Wall -Wno-unused-result -O4 -mno-avx2 -I/usr/local/include", libs => "-L/usr/local/lib64 -L/usr/local/lib -lcollocatordb";
Marc Kupietzbf9bac02022-04-11 21:16:47 +020026#use Inline C => Config => BUILD_NOISY => 1, CFLAGS => $Config{cflags}." -O4 -mtune k9";
27#use Inline C => Config => CLEAN_AFTER_BUILD => 0, ccflags => $Config{ccflags}." -Ofast -march k8 -mtune k8 ";
28
29use Mojo::JSON qw(decode_json encode_json to_json);
Marc Kupietzaf436142026-07-30 14:40:10 +090030use Mojo::Cache;
Marc Kupietzbf9bac02022-04-11 21:16:47 +020031use Exporter qw(import);
32
Marc Kupietz6f317a92026-07-30 15:09:54 +090033our @EXPORT = qw(init_net load_sprofiles mergeVectors getVocabSize getDowntimeCalendar getCollocationAssociation getClassicCollocatorsCached getSimilarProfiles getSimilarProfilesCached getBiggestMergedDifferences getMergedEnd filter_garbage get_neighbours getVecs getWordNumber dump_vecs dump_for_numpy cos_similarity_as_json get_version getPosWiseW2VCollocators configure_cache cache_stats);
Marc Kupietzaf436142026-07-30 14:40:10 +090034
35my $cccache = Mojo::Cache->new(max_keys => $CC_CACHE_MAX_KEYS); # classic collocator cache
36my $spcache = Mojo::Cache->new(max_keys => $SP_CACHE_MAX_KEYS); # similar profile cache
37
38# Adjust the caches at startup, e.g.
39# configure_cache(collocators_max_keys => 500, no_cache => 1)
40# A max_keys value <= 0 disables the respective cache. Setting a limit starts
41# from an empty cache, so that a lowered limit takes effect immediately.
42sub configure_cache {
43 my (%opt) = @_;
44 $opt_C = $opt{no_cache} if defined $opt{no_cache};
45 $cccache = Mojo::Cache->new(max_keys => $opt{collocators_max_keys})
46 if defined $opt{collocators_max_keys};
47 $spcache = Mojo::Cache->new(max_keys => $opt{profiles_max_keys})
48 if defined $opt{profiles_max_keys};
49 return;
50}
51
52sub cache_stats {
53 return {
54 collocators => {
55 keys => scalar keys %{$cccache->{cache} || {}},
56 max_keys => $cccache->max_keys
57 },
58 profiles => {
59 keys => scalar keys %{$spcache->{cache} || {}},
60 max_keys => $spcache->max_keys
61 }
62 };
63}
Marc Kupietzbf9bac02022-04-11 21:16:47 +020064
Marc Kupietz3576c622023-11-05 08:51:58 +010065sub getDowntimeCalendar {
66 my ($url) = @_;
67 if ($url =~ m/^\s*$/) {
68 return "";
69 }
70 my $calendar = LWP::Simple::get($url);
71 return $calendar;
72}
Marc Kupietzbf9bac02022-04-11 21:16:47 +020073
74sub getCollocationAssociation {
75 my ($c, $word, $collocate) = @_;
76 return getCollocationScores($word, $collocate)
77}
78
79sub getClassicCollocatorsCached {
Marc Kupietz3eeec652024-11-18 18:30:04 +010080 my ($c, $word, $compare_to) = @_;
Marc Kupietzbf9bac02022-04-11 21:16:47 +020081 my $s2 = "";
Marc Kupietz6f317a92026-07-30 15:09:54 +090082 # The collocator db is the one of the primary model, which sits at
83 # [merged_end, words) in the merged vocabulary, so its ranks have to be
84 # shifted back before they can be looked up.
85 my $merged_end = getMergedEnd();
86 if($word >= $merged_end) {
87 $word -= $merged_end;
Marc Kupietzbf9bac02022-04-11 21:16:47 +020088 }
89
Marc Kupietz3eeec652024-11-18 18:30:04 +010090 my $pipe;
91 if($compare_to ne "") {
92 $c->app->log->info("comparing syn neighbours to: $compare_to/getClassicCollocators?w=$word");
93 open $pipe, "lwp-request $compare_to/getClassicCollocators?w=$word |";
Marc Kupietzbf9bac02022-04-11 21:16:47 +020094 }
Marc Kupietz3eeec652024-11-18 18:30:04 +010095
Marc Kupietzaf436142026-07-30 14:40:10 +090096 my $collocators = $opt_C ? undef : $cccache->get($word);
97 if(!defined $collocators) {
Marc Kupietzbf9bac02022-04-11 21:16:47 +020098 $c->app->log->info("Getting classic collocates of $word.");
Marc Kupietzaf436142026-07-30 14:40:10 +090099 $collocators = getClassicCollocators($word);
100 $collocators =~ s/:(-?)(nan|inf)/:"${1}${2}"/g;
101 $collocators =~ s/"""/"\\""/g;
102 $cccache->set($word => $collocators) unless $opt_C;
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200103 } else {
104 $c->app->log->info("Getting classic collocates for $word from cache.");
105 }
Marc Kupietz3eeec652024-11-18 18:30:04 +0100106
107 if(defined($pipe)) {
108 while(<$pipe>) {
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200109 $s2 .= $_;
110 }
Marc Kupietz3eeec652024-11-18 18:30:04 +0100111 close($pipe);
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200112 }
113
114 if(length($s2) > 2000) {
Marc Kupietzaf436142026-07-30 14:40:10 +0900115 my $d1 = decode_json($collocators);
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200116 my $d2 = decode_json($s2);
117 my %d2ld;
118 my $minLd = 14;
119 foreach my $i (@{$d2->{collocates}}) {
120 $d2ld{$i->{word}}=$i->{ld};
121 $minLd=$i->{ld} if($i->{ld} < $minLd);
122 }
123 foreach my $i (@{$d1->{collocates}}) {
124 my $w = $i->{word};
125 $i->{delta} = $i->{ld} - (defined $d2ld{$w} ? $d2ld{$w} : $minLd-0.1);
126 }
127 return(encode_json($d1));
128 } else {
Marc Kupietzaf436142026-07-30 14:40:10 +0900129 my $d1 = decode_json($collocators);
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200130 foreach my $i (@{$d1->{collocates}}) {
131 $i->{delta} = 0;
132 }
133 return(encode_json($d1));
134 }
135}
136
137sub getSimilarProfilesCached {
138 my ($c, $word) = @_;
Marc Kupietz6f317a92026-07-30 15:09:54 +0900139 # like the collocator db, the precomputed profiles belong to the primary
140 # model, see getClassicCollocatorsCached()
141 my $merged_end = getMergedEnd();
142 $word -= $merged_end if $word >= $merged_end;
Marc Kupietzaf436142026-07-30 14:40:10 +0900143 my $profiles = $opt_C ? undef : $spcache->get($word);
144 if(!defined $profiles) {
145 $profiles = getSimilarProfiles($word);
146 $spcache->set($word => $profiles) unless $opt_C;
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200147 } else {
148 $c->app->log->info("Getting similar profiles for $word from cache:");
149 }
Marc Kupietzaf436142026-07-30 14:40:10 +0900150 return $profiles;
Marc Kupietzbf9bac02022-04-11 21:16:47 +0200151}
152
153return 1;