Introduce serialization and deserialization of constraint queries
Change-Id: Ib6515bef7c1ea9f909a16463dd73ec5342d2a3c9
diff --git a/lib/Krawfish/Koral/Query/Boundary.pm b/lib/Krawfish/Koral/Query/Boundary.pm
index 2f12b2a..d29d331 100644
--- a/lib/Krawfish/Koral/Query/Boundary.pm
+++ b/lib/Krawfish/Koral/Query/Boundary.pm
@@ -4,7 +4,7 @@
use warnings;
# Serialization helper
-sub boundary {
+sub to_koral_boundary {
my $self = shift;
my %hash = (
'@type' => 'koral:boundary'
@@ -15,6 +15,22 @@
};
+# Deserialization helper
+sub from_koral_boundary {
+ my ($class, $kq) = @_;
+
+ my ($min, $max);
+ if ($kq->{min}) {
+ $min = $kq->{min};
+ };
+ if ($kq->{max}) {
+ $max = $kq->{max};
+ };
+
+ return ($min, $max);
+};
+
+
sub min {
if (defined $_[1]) {
$_[0]->{min} = $_[1];
diff --git a/lib/Krawfish/Koral/Query/Builder.pm b/lib/Krawfish/Koral/Query/Builder.pm
index f213993..6a20daf 100644
--- a/lib/Krawfish/Koral/Query/Builder.pm
+++ b/lib/Krawfish/Koral/Query/Builder.pm
@@ -21,7 +21,7 @@
# TODO: Not all constraints need to be wrapped
use Krawfish::Koral::Query::Constraint::Position;
-use Krawfish::Koral::Query::Constraint::ClassDistance;
+use Krawfish::Koral::Query::Constraint::ClassBetween;
use Krawfish::Koral::Query::Constraint::NotBetween;
use Krawfish::Koral::Query::Constraint::InBetween;
@@ -176,9 +176,9 @@
Krawfish::Koral::Query::Constraint::Position->new(@_);
};
-sub c_class_distance {
+sub c_class_between {
shift;
- Krawfish::Koral::Query::Constraint::ClassDistance->new(@_);
+ Krawfish::Koral::Query::Constraint::ClassBetween->new(@_);
};
sub c_not_between {
diff --git a/lib/Krawfish/Koral/Query/Constraint/Base.pm b/lib/Krawfish/Koral/Query/Constraint/Base.pm
new file mode 100644
index 0000000..1bddd9c
--- /dev/null
+++ b/lib/Krawfish/Koral/Query/Constraint/Base.pm
@@ -0,0 +1,20 @@
+package Krawfish::Koral::Query::Constraint::Base;
+use Role::Tiny;
+use strict;
+use warnings;
+
+requires qw/type to_string optimize min_span max_span/;
+
+# Normalize the constraint (do nothing)
+sub normalize {
+ $_[0];
+};
+
+
+# Identify the constraint (do nothing)
+sub identify {
+ $_[0];
+};
+
+
+1;
diff --git a/lib/Krawfish/Koral/Query/Constraint/ClassBetween.pm b/lib/Krawfish/Koral/Query/Constraint/ClassBetween.pm
new file mode 100644
index 0000000..e2b7ffe
--- /dev/null
+++ b/lib/Krawfish/Koral/Query/Constraint/ClassBetween.pm
@@ -0,0 +1,67 @@
+package Krawfish::Koral::Query::Constraint::ClassBetween;
+use Krawfish::Query::Constraint::ClassBetween;
+use Role::Tiny::With;
+use strict;
+use warnings;
+
+with 'Krawfish::Koral::Query::Constraint::Base';
+
+# This will add a class to the distance between both queries
+
+sub new {
+ my $class = shift;
+ my $nr = shift // 1;
+ bless \$nr, $class;
+};
+
+sub type {
+ 'constr_class';
+};
+
+
+# stringification
+sub to_string {
+ my $self = shift;
+ return 'class=' . $$self;
+};
+
+
+# Optimize the constraint
+sub optimize {
+ my $self = shift;
+ Krawfish::Query::Constraint::ClassBetween->new($$self);
+};
+
+
+# Deserialize
+sub from_koral {
+ my ($class, $kq) = @_;
+ my $nr = $kq->{classOut};
+ return $class->new($nr);
+};
+
+
+# Serialize
+sub to_koral_fragment {
+ my $self = shift;
+ return {
+ '@type' => 'constraint:classBetween',
+ 'classOut' => $$self
+ };
+};
+
+
+# The minimum number of tokens for the constraint
+# Is actual at least one token - but could be optional
+sub min_span {
+ 0;
+};
+
+
+# Maximum number of tokens for the constraint
+sub max_span {
+ -1;
+};
+
+
+1;
diff --git a/lib/Krawfish/Koral/Query/Constraint/ClassDistance.pm b/lib/Krawfish/Koral/Query/Constraint/ClassDistance.pm
deleted file mode 100644
index d8a0d9e..0000000
--- a/lib/Krawfish/Koral/Query/Constraint/ClassDistance.pm
+++ /dev/null
@@ -1,60 +0,0 @@
-package Krawfish::Koral::Query::Constraint::ClassDistance;
-use Krawfish::Query::Constraint::ClassDistance;
-use strict;
-use warnings;
-
-# This will add a class to the distance between both queries
-
-# TODO: Rename to ClassBetween
-
-sub new {
- my $class = shift;
- my $nr = shift // 1;
- bless \$nr, $class;
-};
-
-sub type {
- 'constr_class';
-};
-
-
-# stringification
-sub to_string {
- my $self = shift;
- return 'class=' . $$self;
-};
-
-
-# Normalize the constraint (do nothing)
-sub normalize {
- $_[0];
-};
-
-
-# Identify the constraint (do nothing)
-sub identify {
- $_[0];
-};
-
-
-# Optimize the constraint
-sub optimize {
- my $self = shift;
- Krawfish::Query::Constraint::ClassDistance->new($$self);
-};
-
-
-# The minimum number of tokens for the constraint
-# Is actual at least one token - but could be optional
-sub min_span {
- 0;
-};
-
-
-# Maximum number of tokens for the constraint
-sub max_span {
- -1;
-};
-
-
-1;
diff --git a/lib/Krawfish/Koral/Query/Constraint/InBetween.pm b/lib/Krawfish/Koral/Query/Constraint/InBetween.pm
index d30c307..4355dba 100644
--- a/lib/Krawfish/Koral/Query/Constraint/InBetween.pm
+++ b/lib/Krawfish/Koral/Query/Constraint/InBetween.pm
@@ -1,8 +1,12 @@
package Krawfish::Koral::Query::Constraint::InBetween;
use Krawfish::Query::Constraint::InBetween;
+use Role::Tiny::With;
use strict;
use warnings;
+with 'Krawfish::Koral::Query::Constraint::Base';
+with 'Krawfish::Koral::Query::Boundary';
+
# TODO:
# Support foundry for tokenization
# and gaps parameter.
@@ -25,29 +29,12 @@
# Stringify
sub to_string {
my $self = shift;
- return 'between=' . (defined $self->{min} ? $self->{min} : 0) . '-' . (defined $self->{max} ? $self->{max} : 'INF');
+ return 'between=' . (defined $self->{min} ? $self->{min} : 0) .
+ '-' .
+ (defined $self->{max} ? $self->{max} : 'INF');
};
-sub min {
- my $self = shift;
- if ($_[0]) {
- $self->{min} = shift;
- return $self;
- };
- $self->{min};
-};
-
-
-sub max {
- my $self = shift;
- if ($_[0]) {
- $self->{max} = shift;
- return $self;
- };
- $self->{max};
-};
-
# Normalize constraint
sub normalize {
@@ -67,11 +54,6 @@
};
-sub identify {
- $_[0];
-};
-
-
# Optimize constraint
sub optimize {
my $self = shift;
@@ -110,4 +92,27 @@
};
+# Deserialize
+sub from_koral {
+ my ($class, $kq) = @_;
+
+ return $class->new(
+ $class->from_koral_boundary(
+ $kq->{boundary}
+ )
+ );
+};
+
+
+# serialize
+sub to_koral_fragment {
+ my $self = shift;
+
+ return {
+ '@type' => 'constraint:inBetween',
+ boundary => $self->to_koral_boundary
+ };
+};
+
+
1;
diff --git a/lib/Krawfish/Koral/Query/Constraint/NotBetween.pm b/lib/Krawfish/Koral/Query/Constraint/NotBetween.pm
index 577ac42..21aebf7 100644
--- a/lib/Krawfish/Koral/Query/Constraint/NotBetween.pm
+++ b/lib/Krawfish/Koral/Query/Constraint/NotBetween.pm
@@ -1,11 +1,15 @@
package Krawfish::Koral::Query::Constraint::NotBetween;
+use Role::Tiny::With;
use Krawfish::Query::Constraint::NotBetween;
use Krawfish::Koral::Query::Constraint::InBetween;
-use Krawfish::Koral::Query::Constraint::ClassDistance;
+use Krawfish::Koral::Query::Constraint::ClassBetween;
use Krawfish::Koral::Query::Constraint::Position;
+use Krawfish::Koral::Query::Importer;
use strict;
use warnings;
+with 'Krawfish::Koral::Query::Constraint::Base';
+
# Check that a query between two operands is does nmot occur.
# In case this operand never occurs, it will at least set a relevant length.
@@ -44,7 +48,7 @@
# Wrap out the classes
while ($query->type eq 'class') {
- push @constraints, Krawfish::Koral::Query::Constraint::ClassDistance->new($query->number);
+ push @constraints, Krawfish::Koral::Query::Constraint::ClassBetween->new($query->number);
$query = $query->operand;
};
@@ -129,4 +133,27 @@
};
+# Deserialize
+sub from_koral {
+ my ($class, $kq) = @_;
+
+ my $importer = Krawfish::Koral::Query::Importer->new;
+
+ my $wrap = $kq->{wrap};
+ return $class->new(
+ $importer->from_koral($wrap)
+ );
+};
+
+
+# Serialize
+sub to_koral_fragment {
+ my $self = shift;
+ return {
+ '@type' => 'constraint:notBetween',
+ 'wrap' => $self->{query}->to_koral_fragment
+ };
+};
+
+
1;
diff --git a/lib/Krawfish/Koral/Query/Constraint/Position.pm b/lib/Krawfish/Koral/Query/Constraint/Position.pm
index d321515..bce7bc8 100644
--- a/lib/Krawfish/Koral/Query/Constraint/Position.pm
+++ b/lib/Krawfish/Koral/Query/Constraint/Position.pm
@@ -1,4 +1,5 @@
package Krawfish::Koral::Query::Constraint::Position;
+use Role::Tiny::With;
use parent 'Exporter';
use Krawfish::Query::Constraint::Position;
use feature 'state';
@@ -12,6 +13,8 @@
to_list
MATCHES/;
+with 'Krawfish::Koral::Query::Constraint::Base';
+
# TODO:
# Add error etc. and base this on Krawfish::Query::Constraint::Base.
@@ -191,22 +194,21 @@
};
-sub identify {
- $_[0];
-};
-
+# Optimize constraint
sub optimize {
my $self = shift;
Krawfish::Query::Constraint::Position->new($$self);
};
+# Deserialize
sub from_koral {
my ($class, $kq) = @_;
return $class->new(@{$kq->{frames}});
};
+# serialize
sub to_koral_fragment {
my $self = shift;
return {
@@ -217,4 +219,5 @@
};
};
+
1;
diff --git a/lib/Krawfish/Koral/Query/Importer.pm b/lib/Krawfish/Koral/Query/Importer.pm
index caae132..78b8bfc 100644
--- a/lib/Krawfish/Koral/Query/Importer.pm
+++ b/lib/Krawfish/Koral/Query/Importer.pm
@@ -15,6 +15,9 @@
use Krawfish::Koral::Query::Or;
use Krawfish::Koral::Query::Constraint::Position;
+use Krawfish::Koral::Query::Constraint::ClassBetween;
+use Krawfish::Koral::Query::Constraint::NotBetween;
+use Krawfish::Koral::Query::Constraint::InBetween;
# TODO:
# Merge with Builder!
@@ -87,9 +90,19 @@
shift;
my $kq = shift;
if ($kq->{'@type'} eq 'constraint:position') {
- return Krawfish::Koral::Query::Constraint::Position->new(
- @{$kq->{frames}}
- );
+ return Krawfish::Koral::Query::Constraint::Position->from_koral($kq);
+ }
+
+ elsif ($kq->{'@type'} eq 'constraint:classBetween') {
+ return Krawfish::Koral::Query::Constraint::ClassBetween->from_koral($kq);
+ }
+
+ elsif ($kq->{'@type'} eq 'constraint:notBetween') {
+ return Krawfish::Koral::Query::Constraint::NotBetween->from_koral($kq);
+ }
+
+ elsif ($kq->{'@type'} eq 'constraint:inBetween') {
+ return Krawfish::Koral::Query::Constraint::InBetween->from_koral($kq);
};
warn 'Type ' . $kq->{'@type'} . ' unknown';
diff --git a/lib/Krawfish/Koral/Query/Length.pm b/lib/Krawfish/Koral/Query/Length.pm
index 3326a9d..a0514d9 100644
--- a/lib/Krawfish/Koral/Query/Length.pm
+++ b/lib/Krawfish/Koral/Query/Length.pm
@@ -217,7 +217,7 @@
return {
'@type' => 'koral:group',
operation => 'operation:length',
- boundary => $self->boundary,
+ boundary => $self->to_koral_boundary,
# token => $self->token_base,
operands => [
$self->operand->to_koral_fragment
@@ -233,11 +233,9 @@
my $importer = $class->importer;
my @param = ();
- my $boundary = $kq->{boundary};
- if ($boundary) {
- push @param, $boundary->{min} if $boundary->{min};
- push @param, $boundary->{max} if $boundary->{max};
- };
+ my ($min, $max) = $class->from_koral_boundary($kq->{boundary});
+ push @param, $min if defined $min;
+ push @param, $max if defined $max;
# TODO:
# Not yet implemented
diff --git a/lib/Krawfish/Koral/Query/Repetition.pm b/lib/Krawfish/Koral/Query/Repetition.pm
index 2c09a36..428683c 100644
--- a/lib/Krawfish/Koral/Query/Repetition.pm
+++ b/lib/Krawfish/Koral/Query/Repetition.pm
@@ -75,7 +75,7 @@
return {
'@type' => 'koral:group',
'operation' => 'operation:repetition',
- 'boundary' => $self->boundary,
+ 'boundary' => $self->to_koral_boundary,
'operands' => [
$self->operand->to_koral_fragment
]
@@ -84,15 +84,8 @@
sub from_koral {
my ($class, $kq) = @_;
- my $boundary = $kq->{boundary};
- my ($min, $max);
- if ($boundary->{min}) {
- $min = $boundary->{min};
- };
- if ($boundary->{max}) {
- $max = $boundary->{max};
- };
+ my ($min, $max) = $class->from_koral_boundary($kq->{boundary});
my $importer = $class->importer;
diff --git a/lib/Krawfish/Koral/Util/Sequential.pm b/lib/Krawfish/Koral/Util/Sequential.pm
index d1415e6..2162cfd 100644
--- a/lib/Krawfish/Koral/Util/Sequential.pm
+++ b/lib/Krawfish/Koral/Util/Sequential.pm
@@ -6,6 +6,7 @@
use Krawfish::Query::Nowhere;
use Krawfish::Query::Constraint::Position;
use Krawfish::Query::Constraint::InBetween;
+use Krawfish::Query::Constraint::ClassBetween;
use Krawfish::Query::Constraint;
use List::MoreUtils qw!uniq!;
@@ -1160,7 +1161,7 @@
if ($constraint->{classes}) {
foreach (@{$constraint->{classes}}) {
push @constraints,
- Krawfish::Query::Constraint::ClassDistance->new($_);
+ Krawfish::Query::Constraint::ClassBetween->new($_);
};
};
diff --git a/lib/Krawfish/Query/Constraint/ClassDistance.pm b/lib/Krawfish/Query/Constraint/ClassBetween.pm
similarity index 93%
rename from lib/Krawfish/Query/Constraint/ClassDistance.pm
rename to lib/Krawfish/Query/Constraint/ClassBetween.pm
index 4fddab3..f2f17fb 100644
--- a/lib/Krawfish/Query/Constraint/ClassDistance.pm
+++ b/lib/Krawfish/Query/Constraint/ClassBetween.pm
@@ -1,4 +1,4 @@
-package Krawfish::Query::Constraint::ClassDistance;
+package Krawfish::Query::Constraint::ClassBetween;
use Role::Tiny::With;
use strict;
use warnings;
diff --git a/t/koral/inflate.t b/t/koral/inflate.t
index f721a05..951cfb6 100644
--- a/t/koral/inflate.t
+++ b/t/koral/inflate.t
@@ -66,7 +66,7 @@
# Constraints: One operand is missing
ok($q = $qb->constraint(
[
- $qb->c_class_distance(2)
+ $qb->c_class_between(2)
],
$qb->term_re('[ac].'),
$qb->term_re('b[a]'),
diff --git a/t/koral/query/deserialization.t b/t/koral/query/deserialization.t
index 322057c..b8b676e 100644
--- a/t/koral/query/deserialization.t
+++ b/t/koral/query/deserialization.t
@@ -263,6 +263,70 @@
serialize_deserialize_ok($query);
+
+# group:position, group:disjunction/or
+ok($query = $importer->from_koral({
+ '@type' => 'koral:group',
+ 'operation' => 'operation:constraint',
+ 'constraints' => [
+ {
+ '@type' => 'constraint:position',
+ frames => ['frames:matches']
+ },
+ {
+ '@type' => 'constraint:classBetween',
+ 'classOut' => 5
+ },
+ {
+ '@type' => 'constraint:notBetween',
+ 'wrap' => {
+ '@type' => 'koral:span',
+ wrap => {
+ '@type' => 'koral:term',
+ foundry => 'corenlp',
+ layer => 'p',
+ key => 'V'
+ }
+ }
+ },
+ {
+ '@type' => 'constraint:inBetween',
+ 'boundary' => {
+ '@type' => 'koral:boundary',
+ 'min' => 3,
+ 'max' => 7
+ }
+ }
+
+ ],
+ 'operands' => [{
+ '@type' => 'koral:token',
+ 'wrap' => {
+ '@type' => 'koral:term',
+ 'foundry' => 'tt',
+ 'key' => 'V',
+ 'layer' => 'p'
+ },
+ },{
+ '@type' => 'koral:token',
+ 'wrap' => {
+ '@type' => 'koral:term',
+ 'foundry' => 'opennlp',
+ 'key' => 'V',
+ 'layer' => 'p'
+ },
+ }
+ ]
+}), 'Import Repetition, Span, Term');
+
+
+is($query->to_string,
+ 'constr(pos=matches,class=5,notBetween=<corenlp/p=V>,between=3-7:[tt/p=V],[opennlp/p=V])',
+ 'Stringification');
+
+serialize_deserialize_ok($query);
+
+
diag 'Test deserialization failures';
# E.g.
# - span without wrap
diff --git a/t/query/constraints_class_distance.t b/t/query/constraints_class_between.t
similarity index 94%
rename from t/query/constraints_class_distance.t
rename to t/query/constraints_class_between.t
index cb706a3..493cd16 100644
--- a/t/query/constraints_class_distance.t
+++ b/t/query/constraints_class_between.t
@@ -13,7 +13,7 @@
# This equals to [aa]{5:[]+}[bb]
my $wrap = $qb->constraint(
- [$qb->c_position('precedes'), $qb->c_class_distance(5)],
+ [$qb->c_position('precedes'), $qb->c_class_between(5)],
$qb->token('aa'),
$qb->token('bb')
);
@@ -26,7 +26,7 @@
# This equals to [aa]{5:[]*}[bb]
$wrap = $qb->constraint(
- [$qb->c_position('precedes', 'precedesDirectly'), $qb->c_class_distance(5)],
+ [$qb->c_position('precedes', 'precedesDirectly'), $qb->c_class_between(5)],
$qb->token('aa'),
$qb->token('bb')
);
diff --git a/t/query/constraints_not_between.t b/t/query/constraints_not_between.t
index 68795d5..3513856 100644
--- a/t/query/constraints_not_between.t
+++ b/t/query/constraints_not_between.t
@@ -71,7 +71,7 @@
[
$qb->c_position('precedes'),
$qb->c_not_between($qb->token('dd')),
- $qb->c_class_distance
+ $qb->c_class_between
],
$qb->token('xx'),
$qb->token('xx')