U-SQL JsonTuple - как получить доступ к определенным полям в массиве JSON - PullRequest
0 голосов
/ 14 мая 2019

Я извлекаю данные AVRO с полем JSON, из которого мне нужно получить значения. У JSON есть массив, и я не знаю, в каком порядке могут отображаться различные элементы массива. Как я могу нацелить конкретный узел / значения?

Например, Filters [0] может быть Категория один раз, но может быть AddressType в другой раз.

Я извлекаю данные AVRO - т.е.

@rs =
    EXTRACT date DateTime,
            Body byte[]
    FROM @input_file 
    USING new Microsoft.Analytics.Samples.Formats.ApacheAvro.AvroExtractor(@"
 ...

Тело - это JSON, которое может выглядеть следующим образом (но Category не всегда Filter [0]. Это небольшой пример; существует 7 различных типов "Field"):

{
    ""TimeStamp"": ""2019-02-19T15:00:29.1067771-05:00"",
    ""Filters"": [{
            ""Operator"": ""eq"",
            ""Field"": ""Category"",
            ""Value"": ""Sale""
        }, {
            ""Operator"": ""eq"",
            ""Field"": ""AddressType"",
            ""Value"": ""Home""
        }
    ]
}

Мой U-SQL выглядит так, что, конечно, не всегда работает.

@keyvalues =
    SELECT JsonFunctions.JsonTuple(Encoding.UTF8.GetString(Body), 
        "TimeStamp",
        "$.Filters[?(@.Field == 'Category')].Value",
        "$.Filters[?(@.Field == 'AddressType')].Value"
        ) AS message
    FROM @rs;


@results =
    SELECT 
           message["TimeStamp"] AS TimeStamp,
           message["Filters[0].Value"] AS Category,
           message["Filters[1].Value"] AS AddressType
    FROM @keyvalues;

1 Ответ

0 голосов
/ 20 мая 2019

Хотя на самом деле это не отвечает на мой вопрос, в качестве обходного пути я изменил «образец» метода Microsoft JsonFunctions.JsonTuple, чтобы он мог указывать мое собственное имя ключа для извлеченных значений:

    ///   Added - Prefix a path expression with a specified key.  Use key~$e in the expression.
    ///   eg:
    ///   JsonTuple(json, "myId~id", "myName~name")    -> field names          MAP{ {myId, 1 }, {myName, Ed } }

Модифицированный код:

    private static IEnumerable<KeyValuePair<string, T>> ApplyPath<T>(JToken root, string path)
    {
        var keySeparatorPos = path.IndexOf("~");
        string key = null;
        var searchPath = path;
        if (keySeparatorPos > 0) // =0?if just a leading "=", i.e. no key provided, then don't parse out a key.
        {
            key = path.Substring(0, keySeparatorPos).Trim();
            searchPath = path.Substring(keySeparatorPos + 1);
        }

        // Children
        var children = SelectChildren<T>(root, searchPath);
        foreach (var token in children)
        {
            // Token => T
            var value = (T)JsonFunctions.ConvertToken(token, typeof(T));

            // Tuple(path, value)
            yield return new KeyValuePair<string, T>(key ?? token.Path, value);
        }
    }

Например, я могу получить доступ к вейлам и назвать их

@keyvalues =
    SELECT JsonFunctions.JsonTuple(Encoding.UTF8.GetString(Body), 
        "TimeStamp",
        "EventName",
        "Plan~          $.UrlParams.plan",
        "Category~      $.Filters[?(@.Field == 'Category')].Value",
        "AddressType~   $.Filters[?(@.Field == 'AddressType')].Value"
        ) AS message
    FROM @rs;

@results =
    SELECT 
       message["TimeStamp"]     AS TimeStamp,
       message["EventName"]     AS EventName,
       message["Plan"]          AS Plan,
       message["Category"]      AS Category,
       message["AddressType"]   AS AddressType
    FROM @keyvalues;

(я не проверял, что произойдет, если одно и то же поле появится в массиве несколько раз; в моем случае этого не произойдет)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...