support negated set (denied fields) in FieldSubsetReader

Original commit: elastic/x-pack-elasticsearch@0a54417175
This commit is contained in:
Robert Muir 2016-07-06 16:58:03 -04:00
parent dbe189b064
commit 2583e9cd97
4 changed files with 81 additions and 39 deletions

View File

@ -56,30 +56,33 @@ public final class FieldSubsetReader extends FilterLeafReader {
* and so on.
* @param in reader to filter
* @param fieldNames fields to filter.
* @param negate {@code true} if this should be a negative set, meaning set of field names that is denied.
*/
public static DirectoryReader wrap(DirectoryReader in, Set<String> fieldNames) throws IOException {
return new FieldSubsetDirectoryReader(in, fieldNames);
public static DirectoryReader wrap(DirectoryReader in, Set<String> fieldNames, boolean negate) throws IOException {
return new FieldSubsetDirectoryReader(in, fieldNames, negate);
}
// wraps subreaders with fieldsubsetreaders.
static class FieldSubsetDirectoryReader extends FilterDirectoryReader {
private final Set<String> fieldNames;
private final boolean negate;
FieldSubsetDirectoryReader(DirectoryReader in, final Set<String> fieldNames) throws IOException {
FieldSubsetDirectoryReader(DirectoryReader in, Set<String> fieldNames, boolean negate) throws IOException {
super(in, new FilterDirectoryReader.SubReaderWrapper() {
@Override
public LeafReader wrap(LeafReader reader) {
return new FieldSubsetReader(reader, fieldNames);
return new FieldSubsetReader(reader, fieldNames, negate);
}
});
this.fieldNames = fieldNames;
this.negate = negate;
verifyNoOtherFieldSubsetDirectoryReaderIsWrapped(in);
}
@Override
protected DirectoryReader doWrapDirectoryReader(DirectoryReader in) throws IOException {
return new FieldSubsetDirectoryReader(in, fieldNames);
return new FieldSubsetDirectoryReader(in, fieldNames, negate);
}
public Set<String> getFieldNames() {
@ -111,17 +114,23 @@ public final class FieldSubsetReader extends FilterLeafReader {
/**
* Wrap a single segment, exposing a subset of its fields.
* @param fields set of field names that should be allowed
* @param negate {@code true} if this should be a negative set, meaning set of field names that is denied.
*/
FieldSubsetReader(LeafReader in, Set<String> fieldNames) {
FieldSubsetReader(LeafReader in, Set<String> fields, boolean negate) {
super(in);
// look at what fields the reader has, and preprocess a subset of them that are allowed
ArrayList<FieldInfo> filteredInfos = new ArrayList<>();
for (FieldInfo fi : in.getFieldInfos()) {
if (fieldNames.contains(fi.name)) {
if (fields.contains(fi.name) ^ negate) {
filteredInfos.add(fi);
}
}
fieldInfos = new FieldInfos(filteredInfos.toArray(new FieldInfo[filteredInfos.size()]));
this.fieldNames = fieldNames.toArray(new String[fieldNames.size()]);
fieldNames = new String[filteredInfos.size()];
for (int i = 0; i < fieldNames.length; i++) {
fieldNames[i] = filteredInfos.get(i).name;
}
}
/** returns true if this field is allowed. */

View File

@ -144,7 +144,8 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper {
allowedFields.addAll(mapperService.simpleMatchToIndexNames(field));
}
resolveParentChildJoinFields(allowedFields);
reader = FieldSubsetReader.wrap(reader, allowedFields);
// TODO: support 'denied' fields (pass true as the 3rd parameter in this case)
reader = FieldSubsetReader.wrap(reader, allowedFields, false);
}
return reader;

View File

@ -97,7 +97,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(numDocs));
assertThat(indexFieldDataCache.topLevelBuilds, equalTo(1));
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
global = sortedSetDVOrdinalsIndexFieldData.loadGlobal(ir);
atomic = global.load(ir.leaves().get(0));
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
@ -110,7 +110,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
assertThat(atomic.getOrdinalsValues().getValueCount(), greaterThanOrEqualTo(1L));
}
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
for (LeafReaderContext context : ir.leaves()) {
AtomicOrdinalsFieldData atomic = sortedSetDVOrdinalsIndexFieldData.load(context);
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
@ -126,7 +126,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(numDocs));
assertThat(indexFieldDataCache.topLevelBuilds, equalTo(1));
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
global = pagedBytesIndexFieldData.loadGlobal(ir);
atomic = global.load(ir.leaves().get(0));
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));
@ -141,7 +141,7 @@ public class FieldDataCacheWithFieldSubsetReaderTests extends ESTestCase {
}
assertThat(indexFieldDataCache.leafLevelBuilds, equalTo(ir.leaves().size()));
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet());
DirectoryReader ir = FieldSubsetReader.wrap(this.ir, Collections.<String>emptySet(), false);
for (LeafReaderContext context : ir.leaves()) {
AtomicOrdinalsFieldData atomic = pagedBytesIndexFieldData.load(context);
assertThat(atomic.getOrdinalsValues().getValueCount(), equalTo(0L));

View File

@ -70,7 +70,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -102,7 +102,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -189,7 +189,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -216,7 +216,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -243,7 +243,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -270,7 +270,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -297,7 +297,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -324,7 +324,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -353,7 +353,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Fields vectors = ir.getTermVectors(0);
@ -383,7 +383,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -410,7 +410,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -442,7 +442,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -474,7 +474,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -506,7 +506,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -542,7 +542,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -577,7 +577,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -610,7 +610,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
Set<String> fields = new HashSet<>();
fields.add("fieldA");
fields.add(SourceFieldMapper.NAME);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
Document d2 = ir.document(0);
@ -641,7 +641,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
Set<String> fields = new HashSet<>();
fields.add("fieldA");
fields.add(FieldNamesFieldMapper.NAME);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -690,7 +690,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
fields.add("fieldA");
fields.add("fieldC");
fields.add(FieldNamesFieldMapper.NAME);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only two fields
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -738,7 +738,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
fields.add("fieldA");
fields.add("fieldC");
fields.add(FieldNamesFieldMapper.NAME);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -774,7 +774,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
Set<String> fields = new HashSet<>();
fields.add("fieldA");
fields.add(FieldNamesFieldMapper.NAME);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -803,7 +803,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("id");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
assertEquals(2, ir.numDocs());
assertEquals(1, ir.leaves().size());
@ -838,7 +838,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldB");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// sees no fields
assertNull(ir.getTermVectors(0));
@ -858,7 +858,7 @@ public class FieldSubsetReaderTests extends ESTestCase {
// open reader
Set<String> fields = Collections.singleton("fieldA");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, false);
// see no fields
LeafReader segmentReader = ir.leaves().get(0).reader();
@ -888,9 +888,9 @@ public class FieldSubsetReaderTests extends ESTestCase {
iw.close();
DirectoryReader directoryReader = DirectoryReader.open(dir);
directoryReader = FieldSubsetReader.wrap(directoryReader, Collections.emptySet());
directoryReader = FieldSubsetReader.wrap(directoryReader, Collections.emptySet(), false);
try {
FieldSubsetReader.wrap(directoryReader, Collections.emptySet());
FieldSubsetReader.wrap(directoryReader, Collections.emptySet(), false);
fail("shouldn't be able to wrap FieldSubsetDirectoryReader twice");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), equalTo("Can't wrap [class org.elasticsearch.xpack.security.authz.accesscontrol" +
@ -899,4 +899,36 @@ public class FieldSubsetReaderTests extends ESTestCase {
directoryReader.close();
dir.close();
}
/**
* test filtering two string fields, with negated set
*/
public void testNegative() throws Exception {
Directory dir = newDirectory();
IndexWriterConfig iwc = new IndexWriterConfig(null);
IndexWriter iw = new IndexWriter(dir, iwc);
// add document with 2 fields
Document doc = new Document();
doc.add(new StringField("fieldA", "test", Field.Store.NO));
doc.add(new StringField("fieldB", "test", Field.Store.NO));
iw.addDocument(doc);
// open reader
Set<String> fields = Collections.singleton("fieldB");
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), fields, true);
// see only one field
LeafReader segmentReader = ir.leaves().get(0).reader();
Set<String> seenFields = new HashSet<>();
for (String field : segmentReader.fields()) {
seenFields.add(field);
}
assertEquals(Collections.singleton("fieldA"), seenFields);
assertNotNull(segmentReader.terms("fieldA"));
assertNull(segmentReader.terms("fieldB"));
TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir);
}
}