public override int HandleMap(LazyStringValue key, IEnumerable mapResults, IndexWriteOperation writer, TransactionOperationContext indexContext, IndexingStatsScope stats) { EnsureValidStats(stats); var mappedResult = new DynamicJsonValue(); using (_stats.BlittableJsonAggregation.Start()) { var document = ((Document[])mapResults)[0]; Debug.Assert(key == document.LowerId); foreach (var field in Definition.MapFields.Values) { var autoIndexField = field.As <AutoIndexField>(); switch (autoIndexField.Aggregation) { case AggregationOperation.Count: mappedResult[autoIndexField.Name] = 1; break; case AggregationOperation.Sum: object fieldValue; BlittableJsonTraverser.Default.TryRead(document.Data, autoIndexField.Name, out fieldValue, out _); var arrayResult = fieldValue as IEnumerable <object>; if (arrayResult == null) { // explicitly adding this even if the value isn't there, as a null mappedResult[autoIndexField.Name] = fieldValue; continue; } decimal total = 0; foreach (var item in arrayResult) { if (item == null) { continue; } switch (BlittableNumber.Parse(item, out double doubleValue, out long longValue)) { case NumberParseResult.Double: total += (decimal)doubleValue; break; case NumberParseResult.Long: total += longValue; break; } } mappedResult[autoIndexField.Name] = total; break;
private IEnumerable<AbstractField> GetOrCreateNumericField(IndexField field, object value, Field.Store storage, Field.TermVector termVector = Field.TermVector.NO) { var fieldNameDouble = field.Name + Constants.Documents.Indexing.Fields.RangeFieldSuffixDouble; var fieldNameLong = field.Name + Constants.Documents.Indexing.Fields.RangeFieldSuffixLong; var numericFieldDouble = GetNumericFieldFromCache(fieldNameDouble, null, storage, termVector); var numericFieldLong = GetNumericFieldFromCache(fieldNameLong, null, storage, termVector); switch (BlittableNumber.Parse(value, out double doubleValue, out long longValue)) {
private IEnumerable <AbstractField> GetOrCreateNumericField(IndexField field, object value, Field.Store storage, Field.TermVector termVector = Field.TermVector.NO) { var fieldName = field.Name + Constants.Indexing.Fields.RangeFieldSuffix; var cacheKey = new FieldCacheKey(field.Name, null, storage, termVector, _multipleItemsSameFieldCount.ToArray()); NumericField numericField; CachedFieldItem <NumericField> cached; if (_numericFieldsCache.TryGetValue(cacheKey, out cached) == false) { _numericFieldsCache[cacheKey] = cached = new CachedFieldItem <NumericField> { Field = numericField = new NumericField(CreateFieldName(fieldName), storage, true) }; } else { numericField = cached.Field; } double doubleValue; long longValue; switch (BlittableNumber.Parse(value, out doubleValue, out longValue)) { case NumberParseResult.Double: if (field.SortOption == SortOptions.NumericLong) { yield return(numericField.SetLongValue((long)doubleValue)); } else { yield return(numericField.SetDoubleValue(doubleValue)); } break; case NumberParseResult.Long: if (field.SortOption == SortOptions.NumericDouble) { yield return(numericField.SetDoubleValue(longValue)); } else { yield return(numericField.SetLongValue(longValue)); } break; } }
protected override AggregationResult AggregateOn(List <BlittableJsonReaderObject> aggregationBatch, TransactionOperationContext indexContext, CancellationToken token) { var aggregatedResultsByReduceKey = new Dictionary <BlittableJsonReaderObject, Dictionary <string, PropertyResult> >(ReduceKeyComparer.Instance); foreach (var obj in aggregationBatch) { token.ThrowIfCancellationRequested(); using (obj) { var aggregatedResult = new Dictionary <string, PropertyResult>(); foreach (var propertyName in obj.GetPropertyNames()) { if (_indexDefinition.TryGetField(propertyName, out var indexField)) { switch (indexField.Aggregation) { case AggregationOperation.None: if (obj.TryGet(propertyName, out object groupByValue) == false) { throw new InvalidOperationException($"Could not read group by value of '{propertyName}' property"); } aggregatedResult[propertyName] = new PropertyResult { ResultValue = groupByValue }; break; case AggregationOperation.Count: case AggregationOperation.Sum: object value; if (obj.TryGetMember(propertyName, out value) == false) { throw new InvalidOperationException($"Could not read numeric value of '{propertyName}' property"); } double doubleValue; long longValue; var numberType = BlittableNumber.Parse(value, out doubleValue, out longValue); var aggregate = new PropertyResult(numberType); switch (numberType) { case NumberParseResult.Double: aggregate.ResultValue = aggregate.DoubleValue = doubleValue; break; case NumberParseResult.Long: aggregate.ResultValue = aggregate.LongValue = longValue; break; default: throw new ArgumentOutOfRangeException($"Unknown number type: {numberType}"); } aggregatedResult[propertyName] = aggregate; break; //case FieldMapReduceOperation.None: default: throw new ArgumentOutOfRangeException($"Unhandled field type '{indexField.Aggregation}' to aggregate on"); } } if (_indexDefinition.GroupByFields.ContainsKey(propertyName) == false) { // we want to reuse existing entry to get a reduce key if (obj.Modifications == null) { obj.Modifications = new DynamicJsonValue(obj); } obj.Modifications.Remove(propertyName); } } var reduceKey = indexContext.ReadObject(obj, "reduce key"); if (aggregatedResultsByReduceKey.TryGetValue(reduceKey, out Dictionary <string, PropertyResult> existingAggregate) == false) { aggregatedResultsByReduceKey.Add(reduceKey, aggregatedResult); } else { reduceKey.Dispose(); foreach (var propertyResult in existingAggregate) { propertyResult.Value.Aggregate(aggregatedResult[propertyResult.Key]); } } } } var resultObjects = new List <Document>(aggregatedResultsByReduceKey.Count); foreach (var aggregationResult in aggregatedResultsByReduceKey) { aggregationResult.Key.Dispose(); var djv = new DynamicJsonValue(); foreach (var aggregate in aggregationResult.Value) { djv[aggregate.Key] = aggregate.Value.ResultValue; } resultObjects.Add(new Document { Data = indexContext.ReadObject(djv, "map/reduce") }); } return(new AggregatedDocuments(resultObjects)); }
public override int HandleMap(LazyStringValue key, IEnumerable mapResults, IndexWriteOperation writer, TransactionOperationContext indexContext, IndexingStatsScope stats) { EnsureValidStats(stats); var mappedResult = new DynamicJsonValue(); using (_stats.BlittableJsonAggregation.Start()) { var document = ((Document[])mapResults)[0]; Debug.Assert(key == document.LoweredKey); foreach (var indexField in Definition.MapFields.Values) { switch (indexField.MapReduceOperation) { case FieldMapReduceOperation.Count: mappedResult[indexField.Name] = 1; break; case FieldMapReduceOperation.Sum: object fieldValue; StringSegment leftPath; BlittableJsonTraverser.Default.TryRead(document.Data, indexField.Name, out fieldValue, out leftPath); var arrayResult = fieldValue as IEnumerable <object>; if (arrayResult == null) { // explicitly adding this even if the value isn't there, as a null mappedResult[indexField.Name] = fieldValue; continue; } decimal total = 0; foreach (var item in arrayResult) { if (item == null) { continue; } double doubleValue; long longValue; switch (BlittableNumber.Parse(item, out doubleValue, out longValue)) { case NumberParseResult.Double: total += (decimal)doubleValue; break; case NumberParseResult.Long: total += longValue; break; } } mappedResult[indexField.Name] = total; break; case FieldMapReduceOperation.None: object result; BlittableJsonTraverser.Default.TryRead(document.Data, indexField.Name, out result, out leftPath); // explicitly adding this even if the value isn't there, as a null mappedResult[indexField.Name] = result; break; default: throw new ArgumentOutOfRangeException(); } } _reduceKeyProcessor.Reset(); foreach (var groupByFieldName in Definition.GroupByFields.Keys) { object result; StringSegment leftPath; BlittableJsonTraverser.Default.TryRead(document.Data, groupByFieldName, out result, out leftPath); // explicitly adding this even if the value isn't there, as a null mappedResult[groupByFieldName] = result; _reduceKeyProcessor.Process(indexContext.Allocator, result); } } BlittableJsonReaderObject mr; using (_stats.CreateBlittableJson.Start()) mr = indexContext.ReadObject(mappedResult, key); var mapResult = _singleOutputList[0]; mapResult.Data = mr; mapResult.ReduceKeyHash = _reduceKeyProcessor.Hash; var resultsCount = PutMapResults(key, _singleOutputList, indexContext, stats); DocumentDatabase.Metrics.MapReduceMappedPerSecond.Mark(resultsCount); return(resultsCount); }