public FunctionScoreFunction <T> Weight(double weight)
        {
            var fn = new WeightFunction <T>(weight);

            this._Functions.Add(fn);
            return(fn);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var jo     = JObject.Load(reader);
            var filter = jo.Property("filter")?.Value.ToObject <QueryContainer>(serializer);
            var weight = jo.Property("weight")?.Value.ToObject <double?>();

            ;
            IScoreFunction function = null;

            foreach (var prop in jo.Properties())
            {
                switch (prop.Name)
                {
                case "exp":
                case "gauss":
                case "linear":
                    var properties = prop.Value.Value <JObject>().Properties().ToList();
                    var fieldProp  = properties.First(p => p.Name != "multi_value_mode");
                    var field      = fieldProp.Name;
                    var f          = ReadDecayFunction(prop.Name, fieldProp.Value.Value <JObject>(), serializer);
                    f.Field = field;
                    var mv = properties.FirstOrDefault(p => p.Name == "multi_value_mode")?.Value;
                    if (mv != null)
                    {
                        f.MultiValueMode = serializer.Deserialize <MultiValueMode>(mv.CreateReader());
                    }
                    function = f;

                    break;

                case "random_score":
                    function = FromJson.ReadAs <RandomScoreFunction>(prop.Value.Value <JObject>().CreateReader(), serializer);
                    break;

                case "field_value_factor":
                    function = FromJson.ReadAs <FieldValueFactorFunction>(prop.Value.Value <JObject>().CreateReader(), serializer);
                    break;

                case "script_score":
                    function = FromJson.ReadAs <ScriptScoreFunction>(prop.Value.Value <JObject>().CreateReader(), serializer);
                    break;
                }
            }
            if (function == null && weight.HasValue)
            {
                function = new WeightFunction {
                    Weight = weight
                }
            }
            ;
            else if (function == null)
            {
                return(null);                                   //throw new Exception("error deserializing function score function");
            }
            function.Weight = weight;
            function.Filter = filter;
            return(function);
        }
        public IScoreFunction Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
        {
            QueryContainer filter   = null;
            double?        weight   = null;
            IScoreFunction function = null;

            var count = 0;

            while (reader.ReadIsInObject(ref count))
            {
                var propertyName = reader.ReadPropertyNameSegmentRaw();
                if (AutomataDictionary.TryGetValue(propertyName, out var value))
                {
                    switch (value)
                    {
                    case 0:
                        var formatter = formatterResolver.GetFormatter <QueryContainer>();
                        filter = formatter.Deserialize(ref reader, formatterResolver);
                        break;

                    case 1:
                        weight = reader.ReadDouble();
                        break;

                    case 2:
                        var            innerCount     = 0;
                        MultiValueMode?multiValueMode = null;
                        IDecayFunction decayFunction  = null;
                        while (reader.ReadIsInObject(ref innerCount))
                        {
                            var functionPropertyName = reader.ReadPropertyName();
                            if (functionPropertyName == "multi_value_mode")
                            {
                                multiValueMode = formatterResolver.GetFormatter <MultiValueMode>()
                                                 .Deserialize(ref reader, formatterResolver);
                            }
                            else
                            {
                                var name = propertyName.Utf8String();
                                decayFunction       = ReadDecayFunction(ref reader, name, formatterResolver);
                                decayFunction.Field = functionPropertyName;
                            }
                        }

                        if (decayFunction != null)
                        {
                            decayFunction.MultiValueMode = multiValueMode;
                            function = decayFunction;
                        }
                        break;

                    case 3:
                        var randomScoreFormatter = formatterResolver.GetFormatter <RandomScoreFunction>();
                        function = randomScoreFormatter.Deserialize(ref reader, formatterResolver);
                        break;

                    case 4:
                        var fieldValueFormatter = formatterResolver.GetFormatter <FieldValueFactorFunction>();
                        function = fieldValueFormatter.Deserialize(ref reader, formatterResolver);
                        break;

                    case 5:
                        var scriptFormatter = formatterResolver.GetFormatter <ScriptScoreFunction>();
                        function = scriptFormatter.Deserialize(ref reader, formatterResolver);
                        break;
                    }
                }
            }

            if (function == null)
            {
                if (weight.HasValue)
                {
                    function = new WeightFunction();
                }
                else
                {
                    return(null);
                }
            }

            function.Weight = weight;
            function.Filter = filter;
            return(function);
        }