Algorithm-Classifier-IsolationForest
view release on metacpan or search on metacpan
lib/Algorithm/Classifier/IsolationForest/App/Command/streamd.pm view on Meta::CPAN
[ 's=i', 'Seed int (new models only).' ],
[
'c=f',
'Contamination. Expected fraction of anomalies, in (0, 0.5]; the decision threshold is '
. 'relearned from the window before every save (new models only).'
],
[
't=s@',
'Feature name tag. Pass once per feature; enables the tagged (JSON object) row form '
. '(new models only).'
],
[
'mungers=s',
'JSON file of Algorithm::ToNumberMunger specs, keyed by feature tag (new models only; requires -t).',
{ 'completion' => 'files' }
],
[
'prototype=s',
'JSON prototype file to create the model from (new models only). May not be combined '
. 'with -t or --mungers. See PROTOTYPES in the module POD.',
{ 'completion' => 'files' }
],
);
} ## end sub opt_spec
sub abstract { 'Run an Online Isolation Forest scoring daemon on a Unix socket, speaking JSON lines' }
sub description {
'Runs a prequential scoring daemon around an Online Isolation Forest
model (Algorithm::Classifier::IsolationForest::Online): clients connect
to the Unix domain socket and exchange one JSON document per line.
At startup the daemon resumes from <model-dir>/latest.json when it
exists; otherwise it creates a new model from the creation knobs (-n,
--window, --eta, --growth, --subsample, -s, -c, -t, --mungers,
--prototype -- the same set `iforest stream` takes). The model is saved
to a timestamped file in --model-dir every --save-interval seconds
(only when something was learned), on SIGUSR1, on the save command, and
at shutdown; the symlink latest.json is atomically repointed at every
save, so a restart resumes the stream losing at most one interval.
Requests are JSON objects carrying exactly one of "row", "rows", or
"cmd", an optional "mode", and an optional "tag" (any JSON value,
echoed back verbatim in the reply -- a correlation tag, not to be
confused with feature tags):
{"row": [0.1, 0.7]} -> {"score": 0.41, "label": 0}
{"row": {"cpu": 0.1, "mem": 0.7}} -> {"score": 0.41, "label": 0}
{"rows": [[...], {...}], "tag": "b7"} -> {"scores": [[0.41,0], ...], "tag": "b7"}
{"rows": [[...]], "mode": "learn"} -> {"ok": {"learned": 1}}
{"cmd": "mode", "mode": "score"} -> {"ok": {"mode": "score"}}
{"cmd": "ping"} -> {"ok": "pong"}
{"cmd": "stats"} -> {"ok": {"seen": ..., ...}}
{"cmd": "save"} -> {"ok": {"saved": "oiforest-....json"}}
{"cmd": "relearn-threshold"} -> {"ok": {"threshold": 0.61}}
anything invalid -> {"error": "...", "tag": ...}
The array row form is positional (scalar mungers applied, like stream
CSV input); the object form is a tagged row and runs the full munger
plan, including expanding and combining mungers -- and, being JSON, the
raw values may safely contain commas, newlines, or any unicode.
A worked tagged example. Create the daemon around raw HTTP request
data, with mungers turning the raw values into numbers (mungers.json
here; a --prototype carrying the same schema works identically):
{ "method": { "munger": "http_method_enum", "default": -1 },
"path_len": { "munger": "length", "from": "path" },
"host_entropy": { "munger": "entropy", "from": "host" } }
iforest streamd --set web -t method -t path_len -t host_entropy \
--mungers mungers.json -c 0.05
Clients then send the raw values themselves -- note the input fields
are the munger SOURCES (method, path, host), not the feature tags,
because the plan derives path_len and host_entropy from them:
-> {"row": {"method": "GET", "path": "/index.html",
"host": "www.example.com"}, "tag": "r-1"}
<- {"score": 0.31, "label": 0, "tag": "r-1"}
-> {"row": {"method": "BREW", "path": "/aa,a\"a.php",
"host": "kq3xv9z2.biz"}, "tag": "r-2"}
<- {"score": 0.74, "label": 1, "tag": "r-2"}
The same rows work from the shell via
`iforest streamc --set web --jsonl -i rows.jsonl`.
Modes are prequential (score each row against the model as it stood, then
learn it -- the default), learn (learn only), and score (score only);
"mode" on a row/rows message overrides the connection default set by
the mode command for that message. A bad row gets an {"error": ...}
reply on that message only; the connection and the daemon live on (for
a "rows" batch, rows before the failing one were already processed).
Multiple concurrent connections are supported; rows are applied to the
one shared model in the order their lines arrive, which defines the
stream order.
--set NAME runs a named instance: the set name is appended to
--model-dir (so its saves, latest.json, and default log live under
their own subdirectory) and the socket/pid become <set>.sock /
<set>.pid under the run dir -- with --set, --socket and --pid name the
base run dir instead of the files. Several sets run side by side, each
with its own model, resume state, and double-start protection:
iforest streamd --set web
iforest streamd --set dns --prototype dns-proto.json -c 0.02
Set names must match /\A[A-Za-z0-9+\-@_]+\z/; since the class has no
"." or "/", a set name can only ever create one new path segment.
Everything under --model-dir and the socket/pid directories is created
at startup when missing; when that fails (e.g. running unprivileged
with the /var defaults) the daemon dies immediately, before forking,
naming the directory and the flag to override.
';
} ## end sub description
sub validate {
my ( $self, $opt, $args ) = @_;
( run in 0.718 second using v1.01-cache-2.11-cpan-f52f0507bed )