diff --git a/modules/analyze/webservicefuncs.go b/modules/analyze/webservicefuncs.go index 1487cd1..da957f4 100644 --- a/modules/analyze/webservicefuncs.go +++ b/modules/analyze/webservicefuncs.go @@ -258,14 +258,10 @@ func analysisfuncs(ws *webservice) { } } - includeobjects = ws.Objs.Filter(func(o *engine.Object) bool { - return includequery.Evaluate(o) - }) + includeobjects = query.Execute(includequery, ws.Objs) if excludequery != nil { - excludeobjects = ws.Objs.Filter(func(o *engine.Object) bool { - return excludequery.Evaluate(o) - }) + excludeobjects = query.Execute(excludequery, ws.Objs) } // var methods engine.EdgeBitmap @@ -333,7 +329,7 @@ func analysisfuncs(ws *webservice) { pg.Merge(newpg) } } - // pg = engine.AnalyzePaths(includeobjects.Slice()[0], excludeobjects.Slice()[0], ws.Objs, combinedmethods, engine.Probability(minprobability), 1) + // pg = engine.AnalyzePaths(includeobjects.First(), excludeobjects.First(), ws.Objs, combinedmethods, engine.Probability(minprobability), 1) } else { opts := engine.NewAnalyzeObjectsOptions() opts.IncludeObjects = includeobjects @@ -506,16 +502,10 @@ func analysisfuncs(ws *webservice) { } } - includeobjects = ws.Objs.Filter(func(o *engine.Object) bool { - // Domain Admins and Enterprise Admins groups - return includequery.Evaluate(o) - }) + includeobjects = query.Execute(includequery, ws.Objs) if excludequery != nil { - excludeobjects = ws.Objs.Filter(func(o *engine.Object) bool { - // Domain Admins and Enterprise Admins groups - return excludequery.Evaluate(o) - }) + excludeobjects = query.Execute(excludequery, ws.Objs) } var selectededges []engine.Edge diff --git a/modules/query/execute.go b/modules/query/execute.go new file mode 100644 index 0000000..ae170e0 --- /dev/null +++ b/modules/query/execute.go @@ -0,0 +1,86 @@ +package query + +import ( + "sort" + + "github.com/lkarlslund/adalanche/modules/engine" +) + +type IndexSelectorInfo struct { + a engine.Attribute + match string + results []*engine.Object + queryIndex int +} + +func Execute(q Query, ao *engine.Objects) *engine.Objects { + var potentialindexes []IndexSelectorInfo + switch t := q.(type) { + case andquery: + // Iterate over all subitems + for _, st := range t.subitems { + if qo, ok := st.(QueryOneAttribute); ok { + if sm, ok := qo.q.(hasStringMatch); ok { + // This might be in an index + potentialindexes = append(potentialindexes, IndexSelectorInfo{ + a: qo.a, + match: sm.m, + }) + } + } + } + case QueryOneAttribute: + qo := t + if sm, ok := qo.q.(hasStringMatch); ok { + // This might be in an index + potentialindexes = append(potentialindexes, IndexSelectorInfo{ + a: qo.a, + match: sm.m, + queryIndex: -1, + }) + } + } + + // No optimization possible + if len(potentialindexes) == 0 { + return ao.Filter(q.Evaluate) + } + + for i, potentialIndex := range potentialindexes { + index := ao.GetIndex(potentialIndex.a) + foundObjects, found := index.Lookup(engine.AttributeValueToIndex(engine.AttributeValueString(potentialIndex.match))) + if found { + potentialindexes[i].results = foundObjects + } + } + + sort.Slice(potentialindexes, func(i, j int) bool { + return len(potentialindexes[i].results) < len(potentialindexes[j].results) + }) + + for _, foundindex := range potentialindexes { + if len(foundindex.results) != 0 { + filteredobjects := engine.NewObjects() + + // best working index is first + if foundindex.queryIndex == -1 { + // not an AND query with subitems + for _, o := range foundindex.results { + filteredobjects.Add(o) + } + } else { + // can be optimized by patching out the index matched query filter (remove queryIndex item from filter) + for _, o := range foundindex.results { + if q.Evaluate(o) { + filteredobjects.Add(o) + } + } + } + + return filteredobjects + } + } + + // Return unoptimized filter + return ao.Filter(q.Evaluate) +}