U-SQL programlama kılavuzu - UDT ve UDAGG

Kullanıcı tanımlı türleri kullanma: UDT

Kullanıcı tanımlı türler veya UDT, U-SQL'in bir diğer programlama özelliğidir. U-SQL UDT, normal bir C# kullanıcı tanımlı tür gibi davranır. C# yerleşik ve özel kullanıcı tanımlı türlerin kullanılmasına izin veren kesin olarak belirlenmiş bir dildir.

U-SQL, satır kümelerindeki köşeler arasında UDT geçirildiğinde rastgele UDT'leri örtük olarak seri hale getiremez veya seri durumdan çıkaramaz. Bu, kullanıcının IFormatter arabirimini kullanarak açık bir biçimlendirici sağlaması gerekdiği anlamına gelir. Bu, U-SQL'e UDT için seri hale getirme ve seri durumdan çıkarma yöntemlerini sağlar.

Not

U-SQL'in yerleşik ayıklayıcıları ve çıkışçıları şu anda IFormatter kümesiyle bile UDT verilerini dosyalara veya dosyalara seri durumdan çıkaramaz. Bu nedenle, OUTPUT deyimiyle bir dosyaya UDT verileri yazarken veya ayıklayıcıyla okurken, bunu dize veya bayt dizisi olarak geçirmeniz gerekir. Ardından serileştirme ve seri durumdan çıkarma kodunu (UDT'nin ToString() yöntemi) açıkça çağırırsınız. Kullanıcı tanımlı ayıklayıcılar ve çıkışlayıcılar ise UDT'leri okuyabilir ve yazabilir.

Burada gösterildiği gibi EXTRACTOR veya OUTPUTTER'da (önceki SELECT dışında) UDT kullanmayı denersek:

@rs1 =
    SELECT
        MyNameSpace.Myfunction_Returning_UDT(filed1) AS myfield
    FROM @rs0;

OUTPUT @rs1
    TO @output_file
    USING Outputters.Text();

Aşağıdaki hatayı alırız:

Error	1	E_CSC_USER_INVALIDTYPEINOUTPUTTER: Outputters.Text was used to output column myfield of type
MyNameSpace.Myfunction_Returning_UDT.

Description:

Outputters.Text only supports built-in types.

Resolution:

Implement a custom outputter that knows how to serialize this type, or call a serialization method on the type in
the preceding SELECT.	C:\Users\sergeypu\Documents\Visual Studio 2013\Projects\USQL-Programmability\
USQL-Programmability\Types.usql	52	1	USQL-Programmability

Outputter'da UDT ile çalışmak için, bunu ToString() yöntemiyle dizeye seri hale getirmemiz veya özel bir çıkış oluşturucu oluşturmamız gerekir.

UDF'ler şu anda GROUP BY içinde kullanılamaz. GROUP BY içinde UDT kullanılıyorsa aşağıdaki hata oluşur:

Error	1	E_CSC_USER_INVALIDTYPEINCLAUSE: GROUP BY doesn't support type MyNameSpace.Myfunction_Returning_UDT
for column myfield

Description:

GROUP BY doesn't support UDT or Complex types.

Resolution:

Add a SELECT statement where you can project a scalar column that you want to use with GROUP BY.
C:\Users\sergeypu\Documents\Visual Studio 2013\Projects\USQL-Programmability\USQL-Programmability\Types.usql
62	5	USQL-Programmability

UDT tanımlamak için şunları yapmamız gerekir:

  1. Aşağıdaki ad alanlarını ekleyin:
using Microsoft.Analytics.Interfaces
using System.IO;
  1. UDT arabirimleri için gerekli olan öğesini ekleyin Microsoft.Analytics.Interfaces. Ayrıca, System.IO IFormatter arabirimini tanımlamak için de gerekebilir.

  2. SqlUserDefinedType özniteliğiyle kullanılan tanımlı bir tür tanımlayın.

SqlUserDefinedType , bir derlemedeki tür tanımını U-SQL'de kullanıcı tanımlı tür (UDT) olarak işaretlemek için kullanılır. özniteliğindeki özellikler UDT'nin fiziksel özelliklerini yansıtır. Bu sınıf devralınamaz.

SqlUserDefinedType, UDT tanımı için gerekli bir özniteliktir.

sınıfının oluşturucusunun:

  • SqlUserDefinedTypeAttribute (tür biçimlendirici)

  • Tür biçimlendirici: Bir UDT biçimlendirici tanımlamak için gerekli parametre; özellikle, arabirimin IFormatter türü buraya geçirilmelidir.

[SqlUserDefinedType(typeof(MyTypeFormatter))]
public class MyType
{ … }
  • Tipik UDT, aşağıdaki örnekte gösterildiği gibi IFormatter arabiriminin tanımlanmasını da gerektirir:
public class MyTypeFormatter : IFormatter<MyType>
{
    public void Serialize(MyType instance, IColumnWriter writer, ISerializationContext context)
    { … }

    public MyType Deserialize(IColumnReader reader, ISerializationContext context)
    { … }
}

Arabirim, IFormatter typeparamref name="T" kök türüyle bir nesne grafını serileştirir ve seri durumdan <çıkartır>.

<typeparam name="T">Seri hale getirmek ve seri durumdan çıkarabilmek için nesne grafiğinin kök türü.

  • Seri durumdan çıkarma: Sağlanan akış üzerindeki verileri seri durumdan çıkartır ve nesnelerin grafiğini yeniden oluşturur.

  • Seri hale getirme: Sağlanan akışa verilen kökle bir nesneyi veya nesne grafiğini serileştirir.

MyType örnek: Türün örneği. IColumnWriter yazar / IColumnReader okuyucu: Temel sütun akışı. ISerializationContext context: Serileştirme sırasında akış için kaynak veya hedef bağlamını belirten bir dizi bayrak tanımlayan sabit listesi.

  • Ara: Kaynak veya hedef bağlamın kalıcı bir depo olmadığını belirtir.

  • Kalıcılık: Kaynak veya hedef bağlamın kalıcı bir depo olduğunu belirtir.

Normal bir C# türü olarak, U-SQL UDT tanımı +/==/!=gibi işleçler için geçersiz kılmalar içerebilir. Statik yöntemleri de içerebilir. Örneğin, bu UDT'yi U-SQL MIN toplama işlevine parametre olarak kullanacaksak işleç geçersiz kılmayı tanımlamamız < gerekir.

Bu kılavuzun önceki bölümlerinde, biçimindeki Qn:Pn (Q1:P10)belirli bir tarihten mali dönem tanımlama örneği göstermiştik. Aşağıdaki örnekte, mali dönem değerleri için özel bir türün nasıl tanımlanacağı gösterilmektedir.

Aşağıda, özel UDT ve IFormatter arabirimine sahip arka planda kod bölümü örneği verilmiştir:

[SqlUserDefinedType(typeof(FiscalPeriodFormatter))]
public struct FiscalPeriod
{
    public int Quarter { get; private set; }

    public int Month { get; private set; }

    public FiscalPeriod(int quarter, int month):this()
    {
        this.Quarter = quarter;
        this.Month = month;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }

        return obj is FiscalPeriod && Equals((FiscalPeriod)obj);
    }

    public bool Equals(FiscalPeriod other)
    {
return this.Quarter.Equals(other.Quarter) && this.Month.Equals(other.Month);
    }

    public bool GreaterThan(FiscalPeriod other)
    {
return this.Quarter.CompareTo(other.Quarter) > 0 || this.Month.CompareTo(other.Month) > 0;
    }

    public bool LessThan(FiscalPeriod other)
    {
return this.Quarter.CompareTo(other.Quarter) < 0 || this.Month.CompareTo(other.Month) < 0;
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (this.Quarter.GetHashCode() * 397) ^ this.Month.GetHashCode();
        }
    }

    public static FiscalPeriod operator +(FiscalPeriod c1, FiscalPeriod c2)
    {
return new FiscalPeriod((c1.Quarter + c2.Quarter) > 4 ? (c1.Quarter + c2.Quarter)-4 : (c1.Quarter + c2.Quarter), (c1.Month + c2.Month) > 12 ? (c1.Month + c2.Month) - 12 : (c1.Month + c2.Month));
    }

    public static bool operator ==(FiscalPeriod c1, FiscalPeriod c2)
    {
        return c1.Equals(c2);
    }

    public static bool operator !=(FiscalPeriod c1, FiscalPeriod c2)
    {
        return !c1.Equals(c2);
    }
    public static bool operator >(FiscalPeriod c1, FiscalPeriod c2)
    {
        return c1.GreaterThan(c2);
    }
    public static bool operator <(FiscalPeriod c1, FiscalPeriod c2)
    {
        return c1.LessThan(c2);
    }
    public override string ToString()
    {
        return (String.Format("Q{0}:P{1}", this.Quarter, this.Month));
    }

}

public class FiscalPeriodFormatter : IFormatter<FiscalPeriod>
{
    public void Serialize(FiscalPeriod instance, IColumnWriter writer, ISerializationContext context)
    {
        using (var binaryWriter = new BinaryWriter(writer.BaseStream))
        {
            binaryWriter.Write(instance.Quarter);
            binaryWriter.Write(instance.Month);
            binaryWriter.Flush();
        }
    }

    public FiscalPeriod Deserialize(IColumnReader reader, ISerializationContext context)
    {
        using (var binaryReader = new BinaryReader(reader.BaseStream))
        {
var result = new FiscalPeriod(binaryReader.ReadInt16(), binaryReader.ReadInt16());
            return result;
        }
    }
}

Tanımlanan tür iki sayı içerir: üç aylık dönem ve ay. İşleçler ==/!=/>/< ve statik yöntem ToString() burada tanımlanmıştır.

Daha önce belirtildiği gibi, UDT SELECT ifadelerinde kullanılabilir, ancak özel serileştirme olmadan OUTPUTTER/EXTRACTOR'da kullanılamaz. Bunun ile bir dize ToString() olarak serileştirilmesi veya özel OUTPUTTER/EXTRACTOR ile kullanılması gerekir.

Şimdi UDT kullanımını ele alalım. Arka planda kod içeren bir bölümde GetFiscalPeriod işlevimizi aşağıdaki şekilde değiştirdik:

public static FiscalPeriod GetFiscalPeriodWithCustomType(DateTime dt)
{
    int FiscalMonth = 0;
    if (dt.Month < 7)
    {
        FiscalMonth = dt.Month + 6;
    }
    else
    {
        FiscalMonth = dt.Month - 6;
    }

    int FiscalQuarter = 0;
    if (FiscalMonth >= 1 && FiscalMonth <= 3)
    {
        FiscalQuarter = 1;
    }
    if (FiscalMonth >= 4 && FiscalMonth <= 6)
    {
        FiscalQuarter = 2;
    }
    if (FiscalMonth >= 7 && FiscalMonth <= 9)
    {
        FiscalQuarter = 3;
    }
    if (FiscalMonth >= 10 && FiscalMonth <= 12)
    {
        FiscalQuarter = 4;
    }

    return new FiscalPeriod(FiscalQuarter, FiscalMonth);
}

Gördüğünüz gibi FiscalPeriod türümüzün değerini döndürür.

Burada U-SQL temel betiğinde nasıl daha fazla kullanılacağına yönelik bir örnek sağlıyoruz. Bu örnekte U-SQL betiğinden farklı UDT çağırma biçimleri gösterilmektedir.

DECLARE @input_file string = @"c:\work\cosmos\usql-programmability\input_file.tsv";
DECLARE @output_file string = @"c:\work\cosmos\usql-programmability\output_file.tsv";

@rs0 =
    EXTRACT
        guid string,
        dt DateTime,
        user String,
        des String
    FROM @input_file USING Extractors.Tsv();

@rs1 =
    SELECT
        guid AS start_id,
        dt,
        DateTime.Now.ToString("M/d/yyyy") AS Nowdate,
        USQL_Programmability.CustomFunctions.GetFiscalPeriodWithCustomType(dt).Quarter AS fiscalquarter,
        USQL_Programmability.CustomFunctions.GetFiscalPeriodWithCustomType(dt).Month AS fiscalmonth,
        USQL_Programmability.CustomFunctions.GetFiscalPeriodWithCustomType(dt) + new USQL_Programmability.CustomFunctions.FiscalPeriod(1,7) AS fiscalperiod_adjusted,
        user,
        des
    FROM @rs0;

@rs2 =
    SELECT
        start_id,
        dt,
        DateTime.Now.ToString("M/d/yyyy") AS Nowdate,
        fiscalquarter,
        fiscalmonth,
        USQL_Programmability.CustomFunctions.GetFiscalPeriodWithCustomType(dt).ToString() AS fiscalperiod,

           // This user-defined type was created in the prior SELECT.  Passing the UDT to this subsequent SELECT would have failed if the UDT was not annotated with an IFormatter.
           fiscalperiod_adjusted.ToString() AS fiscalperiod_adjusted,
           user,
           des
    FROM @rs1;

OUTPUT @rs2
    TO @output_file
    USING Outputters.Text();

Aşağıda tam arka planda kod bölümü örneği verilmişti:

using Microsoft.Analytics.Interfaces;
using Microsoft.Analytics.Types.Sql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace USQL_Programmability
{
    public class CustomFunctions
    {
        static public DateTime? ToDateTime(string dt)
        {
            DateTime dtValue;

            if (!DateTime.TryParse(dt, out dtValue))
                return Convert.ToDateTime(dt);
            else
                return null;
        }

        public static FiscalPeriod GetFiscalPeriodWithCustomType(DateTime dt)
        {
            int FiscalMonth = 0;
            if (dt.Month < 7)
            {
                FiscalMonth = dt.Month + 6;
            }
            else
            {
                FiscalMonth = dt.Month - 6;
            }

            int FiscalQuarter = 0;
            if (FiscalMonth >= 1 && FiscalMonth <= 3)
            {
                FiscalQuarter = 1;
            }
            if (FiscalMonth >= 4 && FiscalMonth <= 6)
            {
                FiscalQuarter = 2;
            }
            if (FiscalMonth >= 7 && FiscalMonth <= 9)
            {
                FiscalQuarter = 3;
            }
            if (FiscalMonth >= 10 && FiscalMonth <= 12)
            {
                FiscalQuarter = 4;
            }

            return new FiscalPeriod(FiscalQuarter, FiscalMonth);
        }        [SqlUserDefinedType(typeof(FiscalPeriodFormatter))]
        public struct FiscalPeriod
        {
            public int Quarter { get; private set; }

            public int Month { get; private set; }

            public FiscalPeriod(int quarter, int month):this()
            {
                this.Quarter = quarter;
                this.Month = month;
            }

            public override bool Equals(object obj)
            {
                if (ReferenceEquals(null, obj))
                {
                    return false;
                }

                return obj is FiscalPeriod && Equals((FiscalPeriod)obj);
            }

            public bool Equals(FiscalPeriod other)
            {
return this.Quarter.Equals(other.Quarter) &&    this.Month.Equals(other.Month);
            }

            public bool GreaterThan(FiscalPeriod other)
            {
return this.Quarter.CompareTo(other.Quarter) > 0 || this.Month.CompareTo(other.Month) > 0;
            }

            public bool LessThan(FiscalPeriod other)
            {
return this.Quarter.CompareTo(other.Quarter) < 0 || this.Month.CompareTo(other.Month) < 0;
            }

            public override int GetHashCode()
            {
                unchecked
                {
                    return (this.Quarter.GetHashCode() * 397) ^ this.Month.GetHashCode();
                }
            }

            public static FiscalPeriod operator +(FiscalPeriod c1, FiscalPeriod c2)
            {
return new FiscalPeriod((c1.Quarter + c2.Quarter) > 4 ? (c1.Quarter + c2.Quarter)-4 : (c1.Quarter + c2.Quarter), (c1.Month + c2.Month) > 12 ? (c1.Month + c2.Month) - 12 : (c1.Month + c2.Month));
            }

            public static bool operator ==(FiscalPeriod c1, FiscalPeriod c2)
            {
                return c1.Equals(c2);
            }

            public static bool operator !=(FiscalPeriod c1, FiscalPeriod c2)
            {
                return !c1.Equals(c2);
            }
            public static bool operator >(FiscalPeriod c1, FiscalPeriod c2)
            {
                return c1.GreaterThan(c2);
            }
            public static bool operator <(FiscalPeriod c1, FiscalPeriod c2)
            {
                return c1.LessThan(c2);
            }
            public override string ToString()
            {
                return (String.Format("Q{0}:P{1}", this.Quarter, this.Month));
            }

        }

        public class FiscalPeriodFormatter : IFormatter<FiscalPeriod>
        {
public void Serialize(FiscalPeriod instance, IColumnWriter writer, ISerializationContext context)
            {
                using (var binaryWriter = new BinaryWriter(writer.BaseStream))
                {
                    binaryWriter.Write(instance.Quarter);
                    binaryWriter.Write(instance.Month);
                    binaryWriter.Flush();
                }
            }

public FiscalPeriod Deserialize(IColumnReader reader, ISerializationContext context)
            {
                using (var binaryReader = new BinaryReader(reader.BaseStream))
                {
var result = new FiscalPeriod(binaryReader.ReadInt16(), binaryReader.ReadInt16());
                    return result;
                }
            }
        }
    }
}

Kullanıcı tanımlı toplamaları kullanma: UDAGG

Kullanıcı tanımlı toplamalar, U-SQL ile kullanıma açık olarak gönderilmeden toplamayla ilgili işlevlerdir. Örnek, özel matematik hesaplamaları, dize birleştirmeleri, dizelerle işlemeler vb. gerçekleştirmek için bir toplama olabilir.

Kullanıcı tanımlı toplama temel sınıf tanımı aşağıdaki gibidir:

    [SqlUserDefinedAggregate]
    public abstract class IAggregate<T1, T2, TResult> : IAggregate
    {
        protected IAggregate();

        public abstract void Accumulate(T1 t1, T2 t2);
        public abstract void Init();
        public abstract TResult Terminate();
    }

SqlUserDefinedAggregate , türün kullanıcı tanımlı toplama olarak kaydedilmesi gerektiğini belirtir. Bu sınıf devralınamaz.

SqlUserDefinedType özniteliği UDAGG tanımı için isteğe bağlıdır .

Temel sınıf üç soyut parametre geçirmenizi sağlar: ikisi giriş parametresi, biri sonuç olarak. Veri türleri değişkendir ve sınıf devralma sırasında tanımlanmalıdır.

public class GuidAggregate : IAggregate<string, string, string>
{
    string guid_agg;

    public override void Init()
    { … }

    public override void Accumulate(string guid, string user)
    { … }

    public override string Terminate()
    { … }
}
  • Init , hesaplama sırasında her grup için bir kez çağırır. Her toplama grubu için bir başlatma yordamı sağlar.
  • Biriken her değer için bir kez yürütülür. Toplama algoritması için ana işlevselliği sağlar. Sınıf devralma sırasında tanımlanan çeşitli veri türlerine sahip değerleri toplamak için kullanılabilir. Değişken veri türlerinin iki parametresini kabul edebilir.
  • Sonlandırma işlemi sonunda toplama grubu başına bir kez yürütülür ve her grup için sonuç elde edilir.

Doğru giriş ve çıkış veri türlerini bildirmek için sınıf tanımını aşağıdaki gibi kullanın:

public abstract class IAggregate<T1, T2, TResult> : IAggregate
  • T1: Biriken ilk parametre
  • T2: Biriken ikinci parametre
  • TResult: Sonlandırmanın dönüş türü

Örnek:

public class GuidAggregate : IAggregate<string, int, int>

veya

public class GuidAggregate : IAggregate<string, string, string>

U-SQL'de UDAGG kullanma

UDAGG'yi kullanmak için önce arka planda kod içinde tanımlayın veya daha önce açıklandığı gibi var olan programlanabilirlik DLL'sinden başvuruda bulunun.

Ardından aşağıdaki söz dizimini kullanın:

AGG<UDAGG_functionname>(param1,param2)

Aşağıda UDAGG örneği verilmişti:

public class GuidAggregate : IAggregate<string, string, string>
{
    string guid_agg;

    public override void Init()
    {
        guid_agg = "";
    }

    public override void Accumulate(string guid, string user)
    {
        if (user.ToUpper()== "USER1")
        {
            guid_agg += "{" + guid + "}";
        }
    }

    public override string Terminate()
    {
        return guid_agg;
    }

}

Ve temel U-SQL betiği:

DECLARE @input_file string = @"\usql-programmability\input_file.tsv";
DECLARE @output_file string = @" \usql-programmability\output_file.tsv";

@rs0 =
    EXTRACT
            guid string,
            dt DateTime,
            user String,
            des String
    FROM @input_file
    USING Extractors.Tsv();

@rs1 =
    SELECT
        user,
        AGG<USQL_Programmability.GuidAggregate>(guid,user) AS guid_list
    FROM @rs0
    GROUP BY user;

OUTPUT @rs1 TO @output_file USING Outputters.Text();

Bu kullanım örneği senaryosunda, belirli kullanıcılar için sınıf GUID'lerini birleştiriyoruz.

Sonraki adımlar