Documentation ¶
Overview ¶
Package quamina instances support adding Patterns and then presenting Events, generating a report of which Patterns match the Event. Patterns and Events are both represented as JSON objects, although there is a provided Flattener interface by which structured objects in formats other than JSON can be matched by quamina. Quamina instances match Events quickly and with a latency that is not strongly affected by the number of Patterns which have been added.
Index ¶
Examples ¶
Constants ¶
const MaxBytesInEncoding = 10
const SegmentSeparator = "\n"
Variables ¶
This section is empty.
Functions ¶
func MatcherFromPatterns ¶
MatcherFromPatterns is the main function for building a coreMatcher from a set of patterns. It essentially just builds a trie from the patterns and then converts it to a coreMatcher.
Types ¶
type ArrayPos ¶
ArrayPos represents a Field's position in an Event's structure. Each array in the Event should get an integer which identifies it - in flattenJSON this is accomplished by keeping a counter and giving arrays numbers starting from 0. ArrayPos exists to ensure that Quamina MatchesForEvent will not return a match where two of the matching fields are in separate elements of the same array. Array uniquely identifies an array in an Event. Pos is the Field's index in the Array.
type Field ¶
Field represents a pathname/value combination, one of the data items which is matched against Patterns by the MatchesForEvent API. Path is the \n-separated path from the event root to this field value. Val is the value, a []byte forming a textual representation of the type ArrayTrail, for each array in the Path, identifies the array and the index in it.
type Flattener ¶
type Flattener interface { Flatten(event []byte, tracker SegmentsTreeTracker) ([]Field, error) Copy() Flattener }
nolint:goimports,gofmt Flattener is an interface which provides methods to turn a data structure into a list of path-names and values. The following example illustrates how it works for a JSON object: { "a": 1, "b": "two", "c": true", "d": nil, "e": { "e1": 2, "e2":, 3.02e-5} "f": [33, "x"]} } should produce
"a", "1" "b", "\"two\"", "c", "true" "d", "nil", "e\ne1", "2" "e\ne2", "3.02e-5" "f", "33" "f", "\"x\""
Let's call the first column, eg "d" and "e\ne1", the path. For each step i the path, e.g. "d" and "e1", the Flattener should utilize SegmentsTreeTracker to traverse the hierarchy and select only the needed fields.
type LivePatternsState ¶
type LivePatternsState interface { // Add adds a new pattern or updates an old pattern. // // Note that multiple patterns can be associated with the same X. Add(x X, pattern string) error // Delete removes all patterns associated with the given X and returns the // number of removed patterns. Delete(x X) (int, error) // Iterate calls the given function for every stored pattern. Iterate(func(x X, pattern string) error) error // Contains returns true if x is in the live set; false otherwise. Contains(x X) (bool, error) }
LivePatternsState represents the required capabilities for maintaining the set of live patterns.
type Option ¶
Option is an interface type used in Quamina's New API to pass in options. By convention, Option names have a prefix of "With".
func WithFlattener ¶
WithFlattener allows the specification of a caller-provided Flattener instance to use on incoming Events. This option call may not be provided more than once, nor can it be combined on the same invocation of quamina.New() with the WithMediaType() option.
func WithMediaType ¶
WithMediaType provides a media-type to support the selection of an appropriate Flattener. This option call may not be provided more than once, nor can it be combined on the same invocation of quamina.New() with the WithFlattener() option.
func WithPatternDeletion ¶
WithPatternDeletion arranges, if the argument is true, that this Quamina instance will support the DeletePatterns() method. This option call may not be provided more than once.
func WithPatternStorage ¶
func WithPatternStorage(ps LivePatternsState) Option
WithPatternStorage supplies the Quamina instance with a LivePatternState instance to be used to store the active patterns, i.e. those that have been added with AddPattern but not deleted with DeletePattern. This option call may not be provided more than once.
func WithPatterns ¶
WithPatterns provides a map of patterns to be added to the Quamina instance upon creation. This option allows for bulk pattern addition during initialization.
type Quamina ¶
type Quamina struct {
// contains filtered or unexported fields
}
Quamina instances provide the public APIs of this pattern-matching library. A single Quamina instance is not thread-safe in that it cannot safely be used simultaneously in multiple goroutines. To re-use a Quamina instance concurrently in multiple goroutines, create copies using the Copy API.
func New ¶
New returns a new Quamina instance. Consult the APIs beginning with "With" for the options that may be used to configure the new instance.
Example ¶
package main import ( "fmt" "log" "github.com/DigitalPath-Inc/quamina" ) const userRegisteredEvent = `{ "id": "1c0e1ce4-3d88-4786-a09d-7133c170d02a", "type": "UserRegistered", "user": { "name": "Doe, John", "premiumAccount": true } } ` const premiumUserPattern = `{ "type":["UserRegistered"], "user": {"premiumAccount": [true]} }` func main() { q, err := quamina.New() if err != nil { log.Fatalf("could not create quamina instance: %v", err) } const patternName = "premium user" err = q.AddPattern(patternName, premiumUserPattern) if err != nil { log.Fatalf("could not add pattern: %v", err) } matches, err := q.MatchesForEvent([]byte(userRegisteredEvent)) if err != nil { log.Fatalf("could not match for event: %v", err) } for _, m := range matches { if m == patternName { fmt.Printf("pattern matched for event: %q", patternName) return } } // you would typically handle no matches cases here, but in this example no // match is a bug, hence panic :) panic("no pattern match") }
Output: pattern matched for event: "premium user"
func (*Quamina) AddPattern ¶
AddPattern adds a pattern, identified by the x argument, to a Quamina instance. patternJSON is a JSON object. error is returned in the case that the PatternJSON is invalid JSON or has a leaf which is not provided as an array. AddPattern is single-threaded; if it is invoked concurrently from multiple goroutines (in instances created using the Copy method) calls will block until any other AddPattern call in progress succeeds.
func (*Quamina) Copy ¶
Copy produces a new Quamina instance designed to be used safely in parallel with existing instances on different goroutines. Copy'ed instances share the same underlying data structures, so a pattern added to any instance with AddPattern will be visible in all of them.
func (*Quamina) DeletePatterns ¶
DeletePatterns removes patterns identified by the x argument from the Quamina instance; the effect is that return values from future calls to MatchesForEvent will not include this x value.
func (*Quamina) MatchesForEvent ¶
MatchesForEvent returns a slice of X values which identify patterns that have previously been added to this Quamina instance and which "match" the event in the sense described in README. The matches slice may be empty if no patterns match. error can be returned in case that the event is not a valid JSON object or contains invalid UTF-8 byte sequences.
type SegmentsTreeTracker ¶
type SegmentsTreeTracker interface { // Get returns another level of the hierarchy, referred as "Node" // If a node is returned we will need to traverse into (in JSON/CBOR/ProtoBuf/etc..) Get(segment []byte) (SegmentsTreeTracker, bool) // IsRoot - are we root node? // NOTE: need for early exit, can be solved differently maybe. IsRoot() bool // Called by the Flattener looking at a member name in a JSON object to ascertain // whether this particular member of the object is mentioned in any Patterns added // to the Quamina instance. IsSegmentUsed(segment []byte) bool // When a Flattener reaches the last (leaf) step of a path, this returns the full // path-name for that Field. This is an optimization; since these need to be calculated // while executing `ddPattern, we might as wewll remember them for use during Flattening. PathForSegment(name []byte) []byte // Called by the Flattener to return the number of nodes (non-leaf children) and fields // (field values) contained in any node. When processing through the node, once we've // hit the right number of nodes and fields we can terminate the Flattening process. NodesCount() int FieldsCount() int // String is used only for debugging. String() string }
SegmentsTreeTracker is an interface used by Flattener to represents all the paths mentioned Patterns added to a Quamina instance in AddPattern() calls. It allows a Flattener to determine which Event fields may safely be ignored, and also caches the runtime form of the Field.Path value.
Consider this JSON example:
{ "a": {"b": 1, "c": 2}}
The tree will look like that:
[ root ] | [ "a" ] -> as node |-> with fields of: "b" and "c"
This allow us to traverse the hierarchial data together with the segments tree, fetch a node and answer:
- Is the current segment is used? (JSON - is the current property needs to be selected)
- Do we need to traverse into this Node as well? (JSON - do we need traverse this object?)
- How much fields & nodes we have to traverse in the current hierarchy until we are finished? for example: in the current level, in the tree node we have 1 node and 2 fields we finishded selecting them, can we finish traversing this node?
Source Files ¶
- anything_but.go
- case_folding.go
- core_matcher.go
- doc.go
- field_matcher.go
- flatten_json.go
- flattener.go
- live_pattern_state.go
- match_set.go
- matcher.go
- mermaid_visualizer.go
- monocase.go
- nfa.go
- numbers.go
- numbits.go
- pattern.go
- prettyprinter.go
- pruner.go
- quamina.go
- rebuilding.go
- segments_tree.go
- segments_tree_tracker.go
- shell_style.go
- small_table.go
- stats.go
- trie.go
- trie_mermaid_visualizer.go
- value_matcher.go
- wildcard.go