-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Logs a compact description of druid filters.
--A map is logged that describes the structure of the filter being sent to druid. For each filter it includes a count of the number of instances of that filter.
- Loading branch information
Andrew Cholewa
committed
Dec 8, 2016
1 parent
797cccb
commit 5cb3a13
Showing
4 changed files
with
116 additions
and
0 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
fili-core/src/main/java/com/yahoo/bard/webservice/druid/model/filter/ComplexFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright 2016 Yahoo Inc. | ||
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms. | ||
package com.yahoo.bard.webservice.druid.model.filter; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* A Druid filter that is defined by applying an operation to at least one other filter. For example, {@code not} and | ||
* {@code and} filters are complex. A {@code selector} filter is not. | ||
*/ | ||
public interface ComplexFilter { | ||
|
||
/** | ||
* Returns the filters that are operated on by this filter. | ||
* | ||
* @return The filters operated on by this filter | ||
*/ | ||
List<Filter> getFields(); | ||
} |
59 changes: 59 additions & 0 deletions
59
fili-core/src/main/java/com/yahoo/bard/webservice/logging/blocks/DruidFilterInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright 2016 Yahoo Inc. | ||
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms. | ||
package com.yahoo.bard.webservice.logging.blocks; | ||
|
||
import com.yahoo.bard.webservice.druid.model.filter.ComplexFilter; | ||
import com.yahoo.bard.webservice.druid.model.filter.Filter; | ||
import com.yahoo.bard.webservice.logging.LogInfo; | ||
|
||
import com.fasterxml.jackson.annotation.JsonAutoDetect; | ||
|
||
import java.util.ArrayDeque; | ||
import java.util.Collections; | ||
import java.util.Deque; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Logs some structural data about the filter sent to Druid, without actually logging the entire (potentially massive) | ||
* filter. | ||
*/ | ||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) | ||
public class DruidFilterInfo implements LogInfo { | ||
|
||
protected final Map<String, Long> numEachFilterType; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param filter The filter that needs to be analyzed | ||
*/ | ||
public DruidFilterInfo(Filter filter) { | ||
numEachFilterType = buildFilterCount(filter); | ||
} | ||
|
||
/** | ||
* Performs a DFS search of the filter tree, populating the specified map with the number of instances of each | ||
* filter type appearing in the filter. | ||
* | ||
* @param filter The filter that needs to be traversed | ||
* | ||
* @return A map containing a count of each type of filter | ||
*/ | ||
private Map<String, Long> buildFilterCount(Filter filter) { | ||
if (filter == null) { | ||
return Collections.emptyMap(); | ||
} | ||
Map<String, Long> filterTypeCounter = new LinkedHashMap<>(); | ||
Deque<Filter> filterStack = new ArrayDeque<>(); | ||
filterStack.add(filter); | ||
while (!filterStack.isEmpty()) { | ||
Filter currentFilter = filterStack.pop(); | ||
filterTypeCounter.merge(currentFilter.getClass().getSimpleName(), 1L, (old, increment) -> old + increment); | ||
if (currentFilter instanceof ComplexFilter) { | ||
filterStack.addAll(((ComplexFilter) currentFilter).getFields()); | ||
} | ||
} | ||
return filterTypeCounter; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
...-core/src/test/groovy/com/yahoo/bard/webservice/logging/blocks/DruidFilterInfoSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.yahoo.bard.webservice.logging.blocks | ||
|
||
import com.yahoo.bard.webservice.data.dimension.Dimension | ||
import com.yahoo.bard.webservice.druid.model.filter.AndFilter | ||
import com.yahoo.bard.webservice.druid.model.filter.Filter | ||
import com.yahoo.bard.webservice.druid.model.filter.NotFilter | ||
import com.yahoo.bard.webservice.druid.model.filter.OrFilter | ||
import com.yahoo.bard.webservice.druid.model.filter.SelectorFilter | ||
|
||
import spock.lang.Shared | ||
import spock.lang.Specification | ||
import spock.lang.Unroll | ||
|
||
class DruidFilterInfoSpec extends Specification { | ||
|
||
@Shared Filter selector = new SelectorFilter(Stub(Dimension), "value") | ||
|
||
static final String SELECTOR_NAME = SelectorFilter.class.simpleName | ||
static final String AND_NAME = AndFilter.class.simpleName | ||
static final String OR_NAME = OrFilter.class.simpleName | ||
static final String NOT_NAME = NotFilter.class.simpleName | ||
|
||
@Unroll | ||
def "The DruidFilterInfo correctly analyzes #filter"() { | ||
expect: | ||
new DruidFilterInfo(filter).numEachFilterType == expectedMap | ||
|
||
where: | ||
filter | expectedMap | ||
null | [:] | ||
selector | [(SELECTOR_NAME): 1L] | ||
new AndFilter([selector, selector]) | [(AND_NAME): 1L, (SELECTOR_NAME): 2L] | ||
new NotFilter(new AndFilter([selector, selector])) | [(NOT_NAME): 1L, (AND_NAME): 1L, (SELECTOR_NAME): 2L] | ||
new OrFilter([new AndFilter([selector, selector]), new NotFilter(new AndFilter([selector, selector]))]) | [(OR_NAME): 1L, (AND_NAME): 2L, (NOT_NAME): 1L, (SELECTOR_NAME): 4L] | ||
} | ||
} |