Support empty tags for all WHERE equality operations

A missing tag on a point was sometimes treated as `""` and sometimes
treated as a separate `null` entity. This change modifies the equality
operations to always treat a missing tag as an empty string.

Empty tags are *not* indexed and do not have the same performance as a
tag that exists.

Fixes #3773.
pull/6283/head
Jonathan A. Sternberg 2016-04-11 11:41:42 -04:00
parent ca534bf09f
commit 5bdd61bde7
2 changed files with 50 additions and 22 deletions

View File

@ -13,6 +13,7 @@
- [#6223](https://github.com/influxdata/influxdb/issues/6223): Failure to start/run on Windows. Thanks @mvadu
- [#6229](https://github.com/influxdata/influxdb/issues/6229): Fixed aggregate queries with no GROUP BY to include the end time.
- [#6283](https://github.com/influxdata/influxdb/pull/6283): Fix GROUP BY tag to produce consistent results when a series has no tags.
- [#3773](https://github.com/influxdata/influxdb/issues/3773): Support empty tags for all WHERE equality operations.
## v0.12.0 [2016-04-05]
### Release Notes

View File

@ -763,13 +763,8 @@ func (m *Measurement) idsForExpr(n *influxql.BinaryExpr) (SeriesIDs, influxql.Ex
return m.seriesIDs, n, nil
}
tagVals, ok := m.seriesByTagKeyValue[name.Val]
if name.Val != "_name" && !ok {
if n.Op == influxql.NEQ || n.Op == influxql.NEQREGEX {
return m.seriesIDs, &influxql.BooleanLiteral{Val: true}, nil
}
return nil, nil, nil
}
// Retrieve list of series with this tag key.
tagVals := m.seriesByTagKeyValue[name.Val]
// if we're looking for series with a specific tag value
if str, ok := value.(*influxql.StringLiteral); ok {
@ -784,10 +779,23 @@ func (m *Measurement) idsForExpr(n *influxql.BinaryExpr) (SeriesIDs, influxql.Ex
}
if n.Op == influxql.EQ {
// return series that have a tag of specific value.
ids = tagVals[str.Val]
if str.Val != "" {
// return series that have a tag of specific value.
ids = tagVals[str.Val]
} else {
ids = m.seriesIDs
for k := range tagVals {
ids = ids.Reject(tagVals[k])
}
}
} else if n.Op == influxql.NEQ {
ids = m.seriesIDs.Reject(tagVals[str.Val])
if str.Val != "" {
ids = m.seriesIDs.Reject(tagVals[str.Val])
} else {
for k := range tagVals {
ids = ids.Union(tagVals[k])
}
}
}
return ids, &influxql.BooleanLiteral{Val: true}, nil
}
@ -805,19 +813,38 @@ func (m *Measurement) idsForExpr(n *influxql.BinaryExpr) (SeriesIDs, influxql.Ex
return nil, &influxql.BooleanLiteral{Val: true}, nil
}
// The operation is a NEQREGEX, code must start by assuming all match, even
// series without any tags.
if n.Op == influxql.NEQREGEX {
// Check if we match the empty string to see if we should include series
// that are missing the tag.
empty := re.Val.MatchString("")
// Gather the series that match the regex. If we should include the empty string,
// start with the list of all series and reject series that don't match our condition.
// If we should not include the empty string, include series that match our condition.
if empty && n.Op == influxql.EQREGEX {
ids = m.seriesIDs
}
for k := range tagVals {
match := re.Val.MatchString(k)
if match && n.Op == influxql.EQREGEX {
ids = ids.Union(tagVals[k])
} else if match && n.Op == influxql.NEQREGEX {
ids = ids.Reject(tagVals[k])
for k := range tagVals {
if !re.Val.MatchString(k) {
ids = ids.Reject(tagVals[k])
}
}
} else if empty && n.Op == influxql.NEQREGEX {
for k := range tagVals {
if !re.Val.MatchString(k) {
ids = ids.Union(tagVals[k])
}
}
} else if !empty && n.Op == influxql.EQREGEX {
for k := range tagVals {
if re.Val.MatchString(k) {
ids = ids.Union(tagVals[k])
}
}
} else if !empty && n.Op == influxql.NEQREGEX {
ids = m.seriesIDs
for k := range tagVals {
if re.Val.MatchString(k) {
ids = ids.Reject(tagVals[k])
}
}
}
return ids, &influxql.BooleanLiteral{Val: true}, nil