This commit is contained in:
Markus Cozowicz 2017-09-18 15:08:41 -04:00
Родитель 0f51caf506
Коммит e25a055fbf
35 изменённых файлов: 460 добавлений и 102 удалений

Просмотреть файл

@ -25,6 +25,7 @@
<NuGetPackageImportStamp> <NuGetPackageImportStamp>
</NuGetPackageImportStamp> </NuGetPackageImportStamp>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
<Use64BitIISExpress />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -82,11 +83,11 @@
<Reference Include="Microsoft.Data.Services.Client, Version=5.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.Data.Services.Client, Version=5.8.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.Data.Services.Client.5.8.2\lib\net40\Microsoft.Data.Services.Client.dll</HintPath> <HintPath>$(SolutionDir)\packages\Microsoft.Data.Services.Client.5.8.2\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.16.1.24801, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.9\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath> <HintPath>$(SolutionDir)\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.16.1\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform, Version=3.13.9.1126, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform, Version=3.16.1.24801, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.9\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll</HintPath> <HintPath>$(SolutionDir)\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.16.1\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.Rest.ClientRuntime.2.3.7\lib\net452\Microsoft.Rest.ClientRuntime.dll</HintPath> <HintPath>$(SolutionDir)\packages\Microsoft.Rest.ClientRuntime.2.3.7\lib\net452\Microsoft.Rest.ClientRuntime.dll</HintPath>

Просмотреть файл

@ -11,7 +11,7 @@
<package id="Microsoft.Data.Edm" version="5.8.2" targetFramework="net452" /> <package id="Microsoft.Data.Edm" version="5.8.2" targetFramework="net452" />
<package id="Microsoft.Data.OData" version="5.8.2" targetFramework="net452" /> <package id="Microsoft.Data.OData" version="5.8.2" targetFramework="net452" />
<package id="Microsoft.Data.Services.Client" version="5.8.2" targetFramework="net452" /> <package id="Microsoft.Data.Services.Client" version="5.8.2" targetFramework="net452" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.13.9" targetFramework="net462" /> <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.16.1" targetFramework="net462" />
<package id="Microsoft.Net.Compilers" version="2.1.0" targetFramework="net462" developmentDependency="true" /> <package id="Microsoft.Net.Compilers" version="2.1.0" targetFramework="net462" developmentDependency="true" />
<package id="Microsoft.Rest.ClientRuntime" version="2.3.7" targetFramework="net462" /> <package id="Microsoft.Rest.ClientRuntime" version="2.3.7" targetFramework="net462" />
<package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.6" targetFramework="net462" /> <package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.6" targetFramework="net462" />

Просмотреть файл

@ -1,52 +1,52 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup> </startup>
<runtime> <runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/> <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0"/> <bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0"/> <bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0"/> <bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="VowpalWabbit" publicKeyToken="a76afd1645210483" culture="neutral"/> <assemblyIdentity name="VowpalWabbit" publicKeyToken="a76afd1645210483" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0"/> <bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="VowpalWabbit.Core" publicKeyToken="a76afd1645210483" culture="neutral"/> <assemblyIdentity name="VowpalWabbit.Core" publicKeyToken="a76afd1645210483" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0"/> <bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="VowpalWabbit.Common" publicKeyToken="a76afd1645210483" culture="neutral"/> <assemblyIdentity name="VowpalWabbit.Common" publicKeyToken="a76afd1645210483" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0"/> <bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.ApplicationInsights" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.ApplicationInsights" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0"/> <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/> <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
<system.diagnostics> <system.diagnostics>
<trace autoflush="true" indentsize="0"> <trace autoflush="true" indentsize="0">
<listeners> <listeners>
<add name="myAppInsightsListener" type="Microsoft.ApplicationInsights.TraceListener.ApplicationInsightsTraceListener, Microsoft.ApplicationInsights.TraceListener"/> <add name="myAppInsightsListener" type="Microsoft.ApplicationInsights.TraceListener.ApplicationInsightsTraceListener, Microsoft.ApplicationInsights.TraceListener" />
</listeners> </listeners>
</trace> </trace>
</system.diagnostics> </system.diagnostics>

Просмотреть файл

@ -13,17 +13,31 @@ using System.Threading.Tasks;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Download blobs in background.
/// </summary>
public class AzureBlobBackgroundDownloader : IDisposable public class AzureBlobBackgroundDownloader : IDisposable
{ {
/// <summary>
/// Download finished event handler.
/// </summary>
public delegate void DownloadedEventHandler(object sender, byte[] data); public delegate void DownloadedEventHandler(object sender, byte[] data);
/// <summary>
/// Download failed event handler.
/// </summary>
public delegate void FailedEventHandler(object sender, Exception e); public delegate void FailedEventHandler(object sender, Exception e);
/// <summary>
/// Download finished event handler.
/// </summary>
public event DownloadedEventHandler Downloaded; public event DownloadedEventHandler Downloaded;
/// <summary>
/// Download failed event handler.
/// </summary>
public event FailedEventHandler Failed; public event FailedEventHandler Failed;
private IDisposable disposable; private IDisposable disposable;
private readonly Uri blobAddress; private readonly Uri blobAddress;
@ -32,6 +46,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
private bool downloadImmediately; private bool downloadImmediately;
/// <summary>
/// Creates a new instance.
/// </summary>
public AzureBlobBackgroundDownloader(string blobAddress, TimeSpan interval, bool downloadImmediately = false, string storageConnectionString = null) public AzureBlobBackgroundDownloader(string blobAddress, TimeSpan interval, bool downloadImmediately = false, string storageConnectionString = null)
{ {
if (blobAddress == null) if (blobAddress == null)
@ -120,6 +137,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Disposes the object.
/// </summary>
public void Dispose() public void Dispose()
{ {
if (this.disposable != null) if (this.disposable != null)

Просмотреть файл

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.props" Condition="Exists('$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -55,10 +56,6 @@
<DocumentationFile>$(SolutionDir)bin\x64\Release\Microsoft.Research.MultiWorldTesting.ClientLibrary.XML</DocumentationFile> <DocumentationFile>$(SolutionDir)bin\x64\Release\Microsoft.Research.MultiWorldTesting.ClientLibrary.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="GitLink, Version=2.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\gitlink.2.4.0\lib\net45\GitLink.exe</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AI.PerfCounterCollector, Version=2.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.AI.PerfCounterCollector, Version=2.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.ApplicationInsights.PerfCounterCollector.2.2.0\lib\net45\Microsoft.AI.PerfCounterCollector.dll</HintPath> <HintPath>$(SolutionDir)\packages\Microsoft.ApplicationInsights.PerfCounterCollector.2.2.0\lib\net45\Microsoft.AI.PerfCounterCollector.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -209,6 +206,8 @@
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets'))" /> <Error Condition="!Exists('$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.props'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.targets'))" />
</Target> </Target>
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>$(ProjectDir)\..\docgen.bat "$(ProjectDir)\..\"</PostBuildEvent> <PostBuildEvent>$(ProjectDir)\..\docgen.bat "$(ProjectDir)\..\"</PostBuildEvent>
@ -217,8 +216,8 @@
<AssemblyInfo CodeLanguage="CS" OutputFile="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs" AssemblyTitle="Microsoft.Research.MultiWorldTesting.ClientLibrary" AssemblyDescription="" AssemblyConfiguration="" AssemblyCompany="Microsoft Corp" AssemblyProduct="Microsoft.Research.MultiWorldTesting.ClientLibrary" AssemblyCopyright="Copyright (C) Microsoft Corp 2014-2016" AssemblyTrademark="" ComVisible="false" CLSCompliant="false" Guid="a991c863-165c-4fd5-b388-45b13df358a8" AssemblyVersion="$(ClientLibraryAssemblyVersion)" AssemblyFileVersion="$(ClientLibraryAssemblyVersion)" /> <AssemblyInfo CodeLanguage="CS" OutputFile="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs" AssemblyTitle="Microsoft.Research.MultiWorldTesting.ClientLibrary" AssemblyDescription="" AssemblyConfiguration="" AssemblyCompany="Microsoft Corp" AssemblyProduct="Microsoft.Research.MultiWorldTesting.ClientLibrary" AssemblyCopyright="Copyright (C) Microsoft Corp 2014-2016" AssemblyTrademark="" ComVisible="false" CLSCompliant="false" Guid="a991c863-165c-4fd5-b388-45b13df358a8" AssemblyVersion="$(ClientLibraryAssemblyVersion)" AssemblyFileVersion="$(ClientLibraryAssemblyVersion)" />
</Target> </Target>
<Target Name="AfterBuild"> <Target Name="AfterBuild">
<Exec Command="$(SolutionDir)packages\gitlink.2.4.0\lib\net45\GitLink.exe ..\.. -f $(SolutionDir)\mwt-ds.sln -p $(Platform) -c $(Configuration) -d $(OutDir) -errorsaswarnings -u https://github.com/Microsoft/mwt-ds" Condition="'$(BuildNuget)' == 'true'" />
<Exec Command=".nuget\nuget pack $(ProjectDir)\$(ProjectName).nuspec -Version $(ClientLibraryAssemblyVersion) -Prop &quot;Configuration=Release;Platform=x64&quot; -Prop SolutionDir=$(SolutionDir) -OutputDirectory $(OutDir) " WorkingDirectory="$(SolutionDir)" Condition="'$(BuildNuget)' == 'true'" /> <Exec Command=".nuget\nuget pack $(ProjectDir)\$(ProjectName).nuspec -Version $(ClientLibraryAssemblyVersion) -Prop &quot;Configuration=Release;Platform=x64&quot; -Prop SolutionDir=$(SolutionDir) -OutputDirectory $(OutDir) " WorkingDirectory="$(SolutionDir)" Condition="'$(BuildNuget)' == 'true'" />
</Target> </Target>
<Import Project="$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets" Condition="Exists('$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets')" /> <Import Project="$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets" Condition="Exists('$(SolutionDir)\packages\MSBuildTasks.1.5.0.214\build\MSBuildTasks.targets')" />
<Import Project="$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.targets" Condition="Exists('$(SolutionDir)\packages\GitLink.3.1.0\build\GitLink.targets')" />
</Project> </Project>

Просмотреть файл

@ -2,8 +2,14 @@
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// When a model cannot be found.
/// </summary>
public class ModelNotFoundException : Exception public class ModelNotFoundException : Exception
{ {
/// <summary>
/// Creates a new instance.
/// </summary>
public ModelNotFoundException(string message) : base(message) { } public ModelNotFoundException(string message) : base(message) { }
} }
} }

Просмотреть файл

@ -101,6 +101,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
this.initialized = true; this.initialized = true;
} }
/// <summary>
/// Disposes the resources.
/// </summary>
public void Dispose() public void Dispose()
{ {
foreach (var p in typeof(PerformanceCounters).GetProperties()) foreach (var p in typeof(PerformanceCounters).GetProperties())
@ -115,39 +118,75 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Number of interactions queued.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.NumberOfItems64)] [PerformanceCounterType(PerformanceCounterType.NumberOfItems64)]
public PerformanceCounter InteractionExamplesQueue { get; private set; } public PerformanceCounter InteractionExamplesQueue { get; private set; }
/// <summary>
/// Total number of interactions seen.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.NumberOfItems64)] [PerformanceCounterType(PerformanceCounterType.NumberOfItems64)]
public PerformanceCounter InteractionExamplesTotal { get; private set; } public PerformanceCounter InteractionExamplesTotal { get; private set; }
/// <summary>
/// Number of interactions processed per second.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond32)] [PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond32)]
public PerformanceCounter InteractionExamplesPerSec { get; private set; } public PerformanceCounter InteractionExamplesPerSec { get; private set; }
/// <summary>
/// Number of bytes (from interaction) per second.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond64)] [PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond64)]
public PerformanceCounter InteractionExamplesBytesPerSec { get; private set; } public PerformanceCounter InteractionExamplesBytesPerSec { get; private set; }
/// <summary>
/// Average size of interactions (in bytes).
/// </summary>
[PerformanceCounterType(PerformanceCounterType.AverageCount64)] [PerformanceCounterType(PerformanceCounterType.AverageCount64)]
public PerformanceCounter AverageInteractionExampleSize { get; private set; } public PerformanceCounter AverageInteractionExampleSize { get; private set; }
/// <summary>
/// Average size of interactions (in bytes) - Base.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.AverageBase)] [PerformanceCounterType(PerformanceCounterType.AverageBase)]
public PerformanceCounter AverageInteractionExampleSizeBase { get; private set; } public PerformanceCounter AverageInteractionExampleSizeBase { get; private set; }
/// <summary>
/// Number of observations queued.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.NumberOfItems64)] [PerformanceCounterType(PerformanceCounterType.NumberOfItems64)]
public PerformanceCounter ObservationExamplesQueue { get; private set; } public PerformanceCounter ObservationExamplesQueue { get; private set; }
/// <summary>
/// Total number of observations seen.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.NumberOfItems64)] [PerformanceCounterType(PerformanceCounterType.NumberOfItems64)]
public PerformanceCounter ObservationExamplesTotal { get; private set; } public PerformanceCounter ObservationExamplesTotal { get; private set; }
/// <summary>
/// Number of observations per second.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond32)] [PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond32)]
public PerformanceCounter ObservationExamplesPerSec { get; private set; } public PerformanceCounter ObservationExamplesPerSec { get; private set; }
/// <summary>
/// Number of bytes of observations per second.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond64)] [PerformanceCounterType(PerformanceCounterType.RateOfCountsPerSecond64)]
public PerformanceCounter ObservationExamplesBytesPerSec { get; private set; } public PerformanceCounter ObservationExamplesBytesPerSec { get; private set; }
/// <summary>
/// Average observation size in bytes.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.AverageCount64)] [PerformanceCounterType(PerformanceCounterType.AverageCount64)]
public PerformanceCounter AverageObservationExampleSize { get; private set; } public PerformanceCounter AverageObservationExampleSize { get; private set; }
/// <summary>
/// Average observation size in bytes - Base.
/// </summary>
[PerformanceCounterType(PerformanceCounterType.AverageBase)] [PerformanceCounterType(PerformanceCounterType.AverageBase)]
public PerformanceCounter AverageObservationExampleSizeBase { get; private set; } public PerformanceCounter AverageObservationExampleSizeBase { get; private set; }

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="EnterpriseLibrary.TransientFaultHandling" version="6.0.1304.0" targetFramework="net45" /> <package id="EnterpriseLibrary.TransientFaultHandling" version="6.0.1304.0" targetFramework="net45" />
<package id="gitlink" version="2.4.0" targetFramework="net45" developmentDependency="true" /> <package id="GitLink" version="3.1.0" targetFramework="net462" developmentDependency="true" />
<package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net45" /> <package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net45" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.2.0" targetFramework="net45" /> <package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.2.0" targetFramework="net45" />
<package id="Microsoft.ApplicationInsights.TraceListener" version="2.2.0" targetFramework="net45" /> <package id="Microsoft.ApplicationInsights.TraceListener" version="2.2.0" targetFramework="net45" />

Просмотреть файл

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.Research.MultiWorldTesting.ClientLibrary; using Microsoft.Research.MultiWorldTesting.ClientLibrary;
using System.Threading.Tasks;
namespace ClientDecisionServiceTest namespace ClientDecisionServiceTest
{ {
@ -14,7 +15,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestADFExplorationResult() public async Task TestADFExplorationResult()
{ {
joinServer.Reset(); joinServer.Reset();
@ -36,7 +37,7 @@ namespace ClientDecisionServiceTest
for (int i = 1; i <= 100; i++) for (int i = 1; i <= 100; i++)
{ {
var adfContext = new TestADFContext(i); var adfContext = new TestADFContext(i);
int[] action = ds.ChooseRanking(uniqueKey, adfContext); int[] action = await ds.ChooseRankingAsync(uniqueKey, adfContext);
Assert.AreEqual(i, action.Length); Assert.AreEqual(i, action.Length);
@ -55,7 +56,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestADFModelUpdateFromStream() public async Task TestADFModelUpdateFromStream()
{ {
joinServer.Reset(); joinServer.Reset();
@ -92,7 +93,7 @@ namespace ClientDecisionServiceTest
int numActions = rg.Next(5, 20); int numActions = rg.Next(5, 20);
var context = TestADFContextWithFeatures.CreateRandom(numActions, rg); var context = TestADFContextWithFeatures.CreateRandom(numActions, rg);
int[] action = ds.ChooseRanking(uniqueKey, context); int[] action = await ds.ChooseRankingAsync(uniqueKey, context);
Assert.AreEqual(numActions, action.Length); Assert.AreEqual(numActions, action.Length);

Просмотреть файл

@ -17,7 +17,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestSingleActionDSUploadSingleEvent() public async Task TestSingleActionDSUploadSingleEvent()
{ {
joinServer.Reset(); joinServer.Reset();
@ -35,7 +35,7 @@ namespace ClientDecisionServiceTest
.Create<TestContext>(dsConfig) .Create<TestContext>(dsConfig)
.ExploitUntilModelReady(new ConstantPolicy<TestContext>())) .ExploitUntilModelReady(new ConstantPolicy<TestContext>()))
{ {
chosenAction = ds.ChooseAction(uniqueKey, new TestContext()); chosenAction = await ds.ChooseActionAsync(uniqueKey, new TestContext());
} }
Assert.AreEqual(1, joinServer.RequestCount); Assert.AreEqual(1, joinServer.RequestCount);
@ -48,7 +48,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestSingleActionDSUploadMultipleEvents() public async Task TestSingleActionDSUploadMultipleEvents()
{ {
joinServer.Reset(); joinServer.Reset();
@ -64,8 +64,8 @@ namespace ClientDecisionServiceTest
.ExploitUntilModelReady(new ConstantPolicy<TestContext>())) .ExploitUntilModelReady(new ConstantPolicy<TestContext>()))
{ {
int chosenAction1 = ds.ChooseAction(uniqueKey, new TestContext()); int chosenAction1 = await ds.ChooseActionAsync(uniqueKey, new TestContext());
int chosenAction2 = ds.ChooseAction(uniqueKey, new TestContext()); int chosenAction2 = await ds.ChooseActionAsync(uniqueKey, new TestContext());
ds.ReportReward(1.0f, uniqueKey); ds.ReportReward(1.0f, uniqueKey);
ds.ReportOutcome(JsonConvert.SerializeObject(new { value = "test outcome" }), uniqueKey); ds.ReportOutcome(JsonConvert.SerializeObject(new { value = "test outcome" }), uniqueKey);
} }
@ -148,7 +148,7 @@ namespace ClientDecisionServiceTest
} }
[TestMethod] [TestMethod]
public void TestMultiActionDSUploadSingleEvent() public async Task TestMultiActionDSUploadSingleEvent()
{ {
joinServer.Reset(); joinServer.Reset();
@ -164,7 +164,7 @@ namespace ClientDecisionServiceTest
//.WithTopSlotEpsilonGreedy(.2f) //.WithTopSlotEpsilonGreedy(.2f)
.ExploitUntilModelReady(new ConstantPolicy<TestContext>())) .ExploitUntilModelReady(new ConstantPolicy<TestContext>()))
{ {
chosenActions = ds.ChooseRanking(uniqueKey, new TestContext()); chosenActions = await ds.ChooseRankingAsync(uniqueKey, new TestContext());
} }
Assert.AreEqual(1, joinServer.RequestCount); Assert.AreEqual(1, joinServer.RequestCount);
@ -177,7 +177,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestMultiActionDSUploadMultipleEvents() public async Task TestMultiActionDSUploadMultipleEvents()
{ {
joinServer.Reset(); joinServer.Reset();
@ -191,8 +191,8 @@ namespace ClientDecisionServiceTest
//.WithTopSlotEpsilonGreedy(.2f) //.WithTopSlotEpsilonGreedy(.2f)
.ExploitUntilModelReady(new ConstantPolicy<TestContext>())) .ExploitUntilModelReady(new ConstantPolicy<TestContext>()))
{ {
int[] chosenAction1 = ds.ChooseRanking(uniqueKey, new TestContext()); int[] chosenAction1 = await ds.ChooseRankingAsync(uniqueKey, new TestContext());
int[] chosenAction2 = ds.ChooseRanking(uniqueKey, new TestContext()); int[] chosenAction2 = await ds.ChooseRankingAsync(uniqueKey, new TestContext());
ds.ReportReward(1.0f, uniqueKey); ds.ReportReward(1.0f, uniqueKey);
ds.ReportOutcome(new { value = "test outcome" }, uniqueKey); ds.ReportOutcome(new { value = "test outcome" }, uniqueKey);
} }
@ -202,7 +202,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestMultiActionDSUploadSelective() public async Task TestMultiActionDSUploadSelective()
{ {
joinServer.Reset(); joinServer.Reset();
@ -233,7 +233,7 @@ namespace ClientDecisionServiceTest
{ {
for (int i = 0; i < numEvents; i++) for (int i = 0; i < numEvents; i++)
{ {
int[] chosenAction1 = ds.ChooseRanking(uniqueKey, new TestContext()); int[] chosenAction1 = await ds.ChooseRankingAsync(uniqueKey, new TestContext());
} }
} }
// Some events must have been dropped so the total count cannot be same as original // Some events must have been dropped so the total count cannot be same as original

Просмотреть файл

@ -16,7 +16,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestDevModeSettingsAndExampleLog() public async Task TestDevModeSettingsAndExampleLog()
{ {
joinServer.Reset(); joinServer.Reset();
@ -57,7 +57,7 @@ namespace ClientDecisionServiceTest
Random rg = new Random(i); Random rg = new Random(i);
int numActions = rg.Next(5, 20); int numActions = rg.Next(5, 20);
var context = TestADFContextWithFeatures.CreateRandom(numActions, rg); var context = TestADFContextWithFeatures.CreateRandom(numActions, rg);
int[] action = ds.ChooseRanking(interId, context); int[] action = await ds.ChooseRankingAsync(interId, context);
ds.ReportReward(i / 100f, obserId); ds.ReportReward(i / 100f, obserId);
eventIdList.Add(interId); eventIdList.Add(interId);

Просмотреть файл

@ -31,7 +31,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(0)] [Priority(0)]
public void InitialFullExplorationTest() public async Task InitialFullExplorationTest()
{ {
var recorder = new MyRecorder(); var recorder = new MyRecorder();
@ -53,7 +53,7 @@ namespace ClientDecisionServiceTest
using (var ds = DecisionService.CreateJson(config, metaData:metaData).WithRecorder(recorder)) using (var ds = DecisionService.CreateJson(config, metaData:metaData).WithRecorder(recorder))
{ {
var decision = ds.ChooseRanking("abc", "{\"a\":1,\"_multi\":[{\"b\":2}]}"); var decision = await ds.ChooseRankingAsync("abc", "{\"a\":1,\"_multi\":[{\"b\":2}]}");
// since there's not a model loaded why should get 100% exploration // since there's not a model loaded why should get 100% exploration
// Assert.AreEqual(1f, recorder.LastExplorerState.Probability); // Assert.AreEqual(1f, recorder.LastExplorerState.Probability);
@ -61,7 +61,7 @@ namespace ClientDecisionServiceTest
model.Position = 0; model.Position = 0;
ds.UpdateModel(model); ds.UpdateModel(model);
decision = ds.ChooseRanking("abc", "{\"a\":1,\"_multi\":[{\"b\":2}, {\"b\":3}]}"); decision = await ds.ChooseRankingAsync("abc", "{\"a\":1,\"_multi\":[{\"b\":2}, {\"b\":3}]}");
// Assert.AreNotEqual(1f, recorder.LastExplorerState.Probability); // Assert.AreNotEqual(1f, recorder.LastExplorerState.Probability);
var vwState = recorder.LastMapperState as VWState; var vwState = recorder.LastMapperState as VWState;

Просмотреть файл

@ -95,7 +95,7 @@ namespace ClientDecisionServiceTest
} }
[TestMethod] [TestMethod]
public void TestDSLocalModelUpdate() public async Task TestDSLocalModelUpdate()
{ {
string vwArgs = "--cb_explore_adf --epsilon 0.2 --cb_type dr -q ::"; string vwArgs = "--cb_explore_adf --epsilon 0.2 --cb_type dr -q ::";
DecisionServiceLocal<FoodContext> dsLocal = new DecisionServiceLocal<FoodContext>(vwArgs, 1, TimeSpan.MaxValue); DecisionServiceLocal<FoodContext> dsLocal = new DecisionServiceLocal<FoodContext>(vwArgs, 1, TimeSpan.MaxValue);
@ -107,17 +107,17 @@ namespace ClientDecisionServiceTest
// Generate interactions and ensure the model updates at the right frequency // Generate interactions and ensure the model updates at the right frequency
// (updates every example initially) // (updates every example initially)
prevModel = dsLocal.Model; prevModel = dsLocal.Model;
dsLocal.ChooseAction(guid1, context, 1); await dsLocal.ChooseActionAsync(guid1, context, 1);
dsLocal.ReportRewardAndComplete((float)1.0, guid1); dsLocal.ReportRewardAndComplete((float)1.0, guid1);
Assert.IsTrue(!dsLocal.Model.SequenceEqual(prevModel)); Assert.IsTrue(!dsLocal.Model.SequenceEqual(prevModel));
// Set the model to update every two examples // Set the model to update every two examples
prevModel = dsLocal.Model; prevModel = dsLocal.Model;
dsLocal.ModelUpdateInterval = 2; dsLocal.ModelUpdateInterval = 2;
dsLocal.ChooseAction(guid1, context, 1); await dsLocal.ChooseActionAsync(guid1, context, 1);
dsLocal.ReportRewardAndComplete((float)1.0, guid1); dsLocal.ReportRewardAndComplete((float)1.0, guid1);
Assert.IsFalse(!dsLocal.Model.SequenceEqual(prevModel)); Assert.IsFalse(!dsLocal.Model.SequenceEqual(prevModel));
dsLocal.ChooseAction(guid2, context, 1); await dsLocal.ChooseActionAsync(guid2, context, 1);
dsLocal.ReportRewardAndComplete((float)2.0, guid1); dsLocal.ReportRewardAndComplete((float)2.0, guid1);
Assert.IsTrue(!dsLocal.Model.SequenceEqual(prevModel)); Assert.IsTrue(!dsLocal.Model.SequenceEqual(prevModel));
} }

Просмотреть файл

@ -18,7 +18,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestRcv1ModelUpdateFromStream() public async Task TestRcv1ModelUpdateFromStream()
{ {
joinServer.Reset(); joinServer.Reset();
@ -63,7 +63,7 @@ namespace ClientDecisionServiceTest
DateTime timeStamp = DateTime.UtcNow; DateTime timeStamp = DateTime.UtcNow;
int action = ds.ChooseAction(uniqueKey, context); int action = await ds.ChooseActionAsync(uniqueKey, context);
// verify the actions are in the expected range // verify the actions are in the expected range
Assert.IsTrue(action >= 1 && action <= numActions); Assert.IsTrue(action >= 1 && action <= numActions);

Просмотреть файл

@ -5,6 +5,7 @@ using System;
using System.IO; using System.IO;
using VW.Serializer; using VW.Serializer;
using Microsoft.Research.MultiWorldTesting.Contract; using Microsoft.Research.MultiWorldTesting.Contract;
using System.Threading.Tasks;
namespace ClientDecisionServiceTest namespace ClientDecisionServiceTest
{ {
@ -36,7 +37,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(0)] [Priority(0)]
public void TestSingleActionOfflineModeCustomLogger() public async Task TestSingleActionOfflineModeCustomLogger()
{ {
var dsConfig = new DecisionServiceConfiguration("") { OfflineMode = true, OfflineApplicationID = "" }; var dsConfig = new DecisionServiceConfiguration("") { OfflineMode = true, OfflineApplicationID = "" };
@ -54,7 +55,7 @@ namespace ClientDecisionServiceTest
{ {
for (int i = 0; i < numChooseAction; i++) for (int i = 0; i < numChooseAction; i++)
{ {
ds.ChooseAction(i.ToString(), new TestContext()); await ds.ChooseActionAsync(i.ToString(), new TestContext());
} }
Assert.AreEqual(numChooseAction, recorder.NumRecord); Assert.AreEqual(numChooseAction, recorder.NumRecord);
@ -85,7 +86,7 @@ namespace ClientDecisionServiceTest
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
[Ignore] [Ignore]
public void TestSingleActionOnlineModeCustomLogger() public async Task TestSingleActionOnlineModeCustomLogger()
{ {
var dsConfig = new DecisionServiceConfiguration(MockCommandCenter.SettingsBlobUri) var dsConfig = new DecisionServiceConfiguration(MockCommandCenter.SettingsBlobUri)
{ {
@ -103,7 +104,7 @@ namespace ClientDecisionServiceTest
{ {
for (int i = 0; i < numChooseAction; i++) for (int i = 0; i < numChooseAction; i++)
{ {
ds.ChooseAction(i.ToString(), new TestContext()); await ds.ChooseActionAsync(i.ToString(), new TestContext());
} }
Assert.AreEqual(numChooseAction, recorder.NumRecord); Assert.AreEqual(numChooseAction, recorder.NumRecord);
@ -134,7 +135,7 @@ namespace ClientDecisionServiceTest
[ExpectedException(typeof(Exception))] [ExpectedException(typeof(Exception))]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(0)] [Priority(0)]
public void TestMultiActionOfflineModeArgument() public async Task TestMultiActionOfflineModeArgument()
{ {
var metaData = new ApplicationClientMetadata var metaData = new ApplicationClientMetadata
{ {
@ -145,14 +146,14 @@ namespace ClientDecisionServiceTest
new DecisionServiceConfiguration("") { OfflineMode = true, OfflineApplicationID = "" }, new DecisionServiceConfiguration("") { OfflineMode = true, OfflineApplicationID = "" },
metaData)) metaData))
{ {
ds.ChooseAction("", "{}"); await ds.ChooseActionAsync("", "{}");
} }
} }
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(0)] [Priority(0)]
public void TestMultiActionOfflineModeCustomLogger() public async Task TestMultiActionOfflineModeCustomLogger()
{ {
var dsConfig = new DecisionServiceConfiguration("") { OfflineMode = true, OfflineApplicationID = "" }; var dsConfig = new DecisionServiceConfiguration("") { OfflineMode = true, OfflineApplicationID = "" };
var metaData = new ApplicationClientMetadata var metaData = new ApplicationClientMetadata
@ -168,7 +169,7 @@ namespace ClientDecisionServiceTest
{ {
for (int i = 0; i < numChooseAction; i++) for (int i = 0; i < numChooseAction; i++)
{ {
ds.ChooseAction(i.ToString(), new TestContext()); await ds.ChooseActionAsync(i.ToString(), new TestContext());
} }
Assert.AreEqual(numChooseAction, recorder.NumRecord); Assert.AreEqual(numChooseAction, recorder.NumRecord);
@ -197,7 +198,7 @@ namespace ClientDecisionServiceTest
[TestMethod] [TestMethod]
[TestCategory("Client Library")] [TestCategory("Client Library")]
[Priority(1)] [Priority(1)]
public void TestMultiActionOnlineModeCustomLogger() public async Task TestMultiActionOnlineModeCustomLogger()
{ {
joinServer.Reset(); joinServer.Reset();
@ -216,7 +217,7 @@ namespace ClientDecisionServiceTest
{ {
for (int i = 0; i < numChooseAction; i++) for (int i = 0; i < numChooseAction; i++)
{ {
ds.ChooseAction(i.ToString(), new TestContext()); await ds.ChooseActionAsync(i.ToString(), new TestContext());
} }
Assert.AreEqual(numChooseAction, recorder.NumRecord); Assert.AreEqual(numChooseAction, recorder.NumRecord);

Просмотреть файл

@ -1,43 +1,43 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<runtime> <runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/> <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0"/> <bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0"/> <bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0"/> <bindingRedirect oldVersion="0.0.0.0-5.8.1.0" newVersion="5.8.1.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="VowpalWabbit.Core" publicKeyToken="a76afd1645210483" culture="neutral"/> <assemblyIdentity name="VowpalWabbit.Core" publicKeyToken="a76afd1645210483" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0"/> <bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="VowpalWabbit" publicKeyToken="a76afd1645210483" culture="neutral"/> <assemblyIdentity name="VowpalWabbit" publicKeyToken="a76afd1645210483" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0"/> <bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="VowpalWabbit.Common" publicKeyToken="a76afd1645210483" culture="neutral"/> <assemblyIdentity name="VowpalWabbit.Common" publicKeyToken="a76afd1645210483" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0"/> <bindingRedirect oldVersion="0.0.0.0-8.4.0.0" newVersion="8.4.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.ApplicationInsights" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.ApplicationInsights" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0"/> <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral"/> <assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0"/> <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" /></startup></configuration>

Просмотреть файл

@ -7,18 +7,34 @@ using VW.Serializer;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Base class for all Vowpal Wabbit contenxt mappers.
/// </summary>
public abstract class VWBaseContextMapper<TVowpalWabbit, TContext, TAction> public abstract class VWBaseContextMapper<TVowpalWabbit, TContext, TAction>
: IUpdatable<Stream>, IDisposable, IContextMapper<TContext, TAction> : IUpdatable<Stream>, IDisposable, IContextMapper<TContext, TAction>
where TVowpalWabbit : class, IDisposable where TVowpalWabbit : class, IDisposable
{ {
/// <summary>
/// Type inspector used to extract schema information.
/// </summary>
protected ITypeInspector typeInspector; protected ITypeInspector typeInspector;
/// <summary>
/// The pool of VW objects.
/// </summary>
protected VowpalWabbitThreadedPredictionBase<TVowpalWabbit> vwPool; protected VowpalWabbitThreadedPredictionBase<TVowpalWabbit> vwPool;
/// <summary>
/// True if development mode enabled (additional logging).
/// </summary>
protected bool developmentMode; protected bool developmentMode;
/// <summary> /// <summary>
/// Constructor using a memory stream. /// Constructor using a memory stream.
/// </summary> /// </summary>
/// <param name="vwModelStream">The VW model memory stream.</param> /// <param name="vwModelStream">The VW model memory stream.</param>
/// <param name="developmentMode">True if development mode enabled (additional logging).</param>
/// <param name="typeInspector">Type inspector used to extract schema information.</param>
protected VWBaseContextMapper( protected VWBaseContextMapper(
Stream vwModelStream = null, Stream vwModelStream = null,
ITypeInspector typeInspector = null, ITypeInspector typeInspector = null,
@ -86,6 +102,13 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
public Task<PolicyDecision<TAction>> MapContextAsync(TContext context) public Task<PolicyDecision<TAction>> MapContextAsync(TContext context)
{ {
if (this.vwPool == null) if (this.vwPool == null)
@ -100,8 +123,19 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected abstract VowpalWabbitThreadedPredictionBase<TVowpalWabbit> CreatePool(VowpalWabbitSettings settings); protected abstract VowpalWabbitThreadedPredictionBase<TVowpalWabbit> CreatePool(VowpalWabbitSettings settings);
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected abstract PolicyDecision<TAction> MapContext(TVowpalWabbit vw, TContext context); protected abstract PolicyDecision<TAction> MapContext(TVowpalWabbit vw, TContext context);
} }
} }

Просмотреть файл

@ -8,6 +8,10 @@ using VW.Serializer;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Vowpal Wabbit based explorer using C# based features.
/// </summary>
/// <typeparam name="TContext"></typeparam>
public sealed class VWExplorer<TContext> : public sealed class VWExplorer<TContext> :
VWBaseContextMapper<VowpalWabbit<TContext>, TContext, ActionProbability[]>, VWBaseContextMapper<VowpalWabbit<TContext>, TContext, ActionProbability[]>,
IContextMapper<TContext, ActionProbability[]>, INumberOfActionsProvider<TContext> IContextMapper<TContext, ActionProbability[]>, INumberOfActionsProvider<TContext>
@ -18,7 +22,6 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
/// <summary> /// <summary>
/// Constructor using a memory stream. /// Constructor using a memory stream.
/// </summary> /// </summary>
/// <param name="vwModelStream">The VW model memory stream.</param>
public VWExplorer(Stream vwModelStream = null, ITypeInspector typeInspector = null, bool developmentMode = false) public VWExplorer(Stream vwModelStream = null, ITypeInspector typeInspector = null, bool developmentMode = false)
: base(vwModelStream, typeInspector, developmentMode) : base(vwModelStream, typeInspector, developmentMode)
{ {
@ -32,11 +35,22 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
this.multiSerializer = this.serializer as IVowpalWabbitMultiExampleSerializerCompiler<TContext>; this.multiSerializer = this.serializer as IVowpalWabbitMultiExampleSerializerCompiler<TContext>;
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext>> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext>> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction<TContext>(settings); return new VowpalWabbitThreadedPrediction<TContext>(settings);
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<ActionProbability[]> MapContext(VowpalWabbit<TContext> vw, TContext context) protected override PolicyDecision<ActionProbability[]> MapContext(VowpalWabbit<TContext> vw, TContext context)
{ {
if (this.developmentMode) if (this.developmentMode)
@ -63,6 +77,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
return PolicyDecision.Create(ap, state); return PolicyDecision.Create(ap, state);
} }
/// <summary>
/// Returns the number of actions defined by this context.
/// </summary>
public int GetNumberOfActions(TContext context) public int GetNumberOfActions(TContext context)
{ {
if (this.multiSerializer == null) if (this.multiSerializer == null)

Просмотреть файл

@ -7,15 +7,29 @@ using System;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Vowpal Wabbit based policy for string JSON based context.
/// </summary>
public class VWJsonPolicy : public class VWJsonPolicy :
VWBaseContextMapper<VowpalWabbit, string, int>, VWBaseContextMapper<VowpalWabbit, string, int>,
IPolicy<string> IPolicy<string>
{ {
/// <summary>
/// Creates a new instance.
/// </summary>
public VWJsonPolicy(Stream vwModelStream = null) public VWJsonPolicy(Stream vwModelStream = null)
: base(vwModelStream) : base(vwModelStream)
{ {
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<int> MapContext(VowpalWabbit vw, string context) protected override PolicyDecision<int> MapContext(VowpalWabbit vw, string context)
{ {
using (var vwJson = new VowpalWabbitJsonSerializer(vw)) using (var vwJson = new VowpalWabbitJsonSerializer(vw))
@ -28,26 +42,46 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction(settings); return new VowpalWabbitThreadedPrediction(settings);
} }
} }
/// <summary>
/// Vowpal Wabbit based ranker for string JSON based context.
/// </summary>
public class VWJsonRanker : public class VWJsonRanker :
VWBaseContextMapper<VowpalWabbit, string, int[]>, VWBaseContextMapper<VowpalWabbit, string, int[]>,
IRanker<string>, INumberOfActionsProvider<string> IRanker<string>, INumberOfActionsProvider<string>
{ {
/// <summary>
/// Creates a new instance.
/// </summary>
public VWJsonRanker(Stream vwModelStream = null) public VWJsonRanker(Stream vwModelStream = null)
: base(vwModelStream) : base(vwModelStream)
{ {
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction(settings); return new VowpalWabbitThreadedPrediction(settings);
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<int[]> MapContext(VowpalWabbit vw, string context) protected override PolicyDecision<int[]> MapContext(VowpalWabbit vw, string context)
{ {
using (var vwJson = new VowpalWabbitJsonSerializer(vw)) using (var vwJson = new VowpalWabbitJsonSerializer(vw))
@ -63,6 +97,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Returns the number of actions defined by this context.
/// </summary>
public int GetNumberOfActions(string context) public int GetNumberOfActions(string context)
{ {
return VowpalWabbitJsonSerializer.GetNumberOfActionDependentExamples(context); return VowpalWabbitJsonSerializer.GetNumberOfActionDependentExamples(context);

Просмотреть файл

@ -11,20 +11,37 @@ using VW.Serializer;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Vowpal Wabbit based explorer for JSON context.
/// </summary>
public sealed class VWJsonExplorer : public sealed class VWJsonExplorer :
VWBaseContextMapper<VowpalWabbit, string, ActionProbability[]>, VWBaseContextMapper<VowpalWabbit, string, ActionProbability[]>,
IContextMapper<string, ActionProbability[]>, INumberOfActionsProvider<string> IContextMapper<string, ActionProbability[]>, INumberOfActionsProvider<string>
{ {
/// <summary>
/// Creates a new instance.
/// </summary>
public VWJsonExplorer(Stream vwModelStream = null, bool developmentMode = false) public VWJsonExplorer(Stream vwModelStream = null, bool developmentMode = false)
: base(vwModelStream, developmentMode: developmentMode) : base(vwModelStream, developmentMode: developmentMode)
{ {
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction(settings); return new VowpalWabbitThreadedPrediction(settings);
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<ActionProbability[]> MapContext(VowpalWabbit vw, string context) protected override PolicyDecision<ActionProbability[]> MapContext(VowpalWabbit vw, string context)
{ {
using (var vwJson = new VowpalWabbitJsonSerializer(vw)) using (var vwJson = new VowpalWabbitJsonSerializer(vw))
@ -50,6 +67,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
} }
} }
/// <summary>
/// Returns the number of actions defined by this context.
/// </summary>
public int GetNumberOfActions(string context) public int GetNumberOfActions(string context)
{ {
return VowpalWabbitJsonSerializer.GetNumberOfActionDependentExamples(context); return VowpalWabbitJsonSerializer.GetNumberOfActionDependentExamples(context);

Просмотреть файл

@ -6,23 +6,37 @@ using VW.Serializer;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Vowpal Wabbit based policy.
/// </summary>
/// <typeparam name="TContext"></typeparam>
public class VWPolicy<TContext> public class VWPolicy<TContext>
: VWBaseContextMapper<VowpalWabbit<TContext>, TContext, int>, IPolicy<TContext> : VWBaseContextMapper<VowpalWabbit<TContext>, TContext, int>, IPolicy<TContext>
{ {
/// <summary> /// <summary>
/// Constructor using a memory stream. /// Constructor using a memory stream.
/// </summary> /// </summary>
/// <param name="vwModelStream">The VW model memory stream.</param>
public VWPolicy(Stream vwModelStream = null, ITypeInspector typeInspector = null, bool developmentMode = false) public VWPolicy(Stream vwModelStream = null, ITypeInspector typeInspector = null, bool developmentMode = false)
: base(vwModelStream, typeInspector, developmentMode) : base(vwModelStream, typeInspector, developmentMode)
{ {
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext>> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext>> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction<TContext>(settings); return new VowpalWabbitThreadedPrediction<TContext>(settings);
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<int> MapContext(VowpalWabbit<TContext> vw, TContext context) protected override PolicyDecision<int> MapContext(VowpalWabbit<TContext> vw, TContext context)
{ {
if (this.developmentMode) if (this.developmentMode)

Просмотреть файл

@ -9,6 +9,10 @@ using VW.Serializer;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Vowpal Wabbit based ranker.
/// </summary>
/// <typeparam name="TContext"></typeparam>
public class VWRanker<TContext> : public class VWRanker<TContext> :
VWBaseContextMapper<VowpalWabbit<TContext>, TContext, int[]>, VWBaseContextMapper<VowpalWabbit<TContext>, TContext, int[]>,
IRanker<TContext>, INumberOfActionsProvider<TContext> IRanker<TContext>, INumberOfActionsProvider<TContext>
@ -18,7 +22,6 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
/// <summary> /// <summary>
/// Constructor using a memory stream. /// Constructor using a memory stream.
/// </summary> /// </summary>
/// <param name="vwModelStream">The VW model memory stream.</param>
public VWRanker(Stream vwModelStream = null, ITypeInspector typeInspector = null, bool developmentMode = false) public VWRanker(Stream vwModelStream = null, ITypeInspector typeInspector = null, bool developmentMode = false)
: base(vwModelStream, typeInspector, developmentMode) : base(vwModelStream, typeInspector, developmentMode)
{ {
@ -30,11 +33,22 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
}) as IVowpalWabbitMultiExampleSerializerCompiler<TContext>; }) as IVowpalWabbitMultiExampleSerializerCompiler<TContext>;
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext>> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext>> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction<TContext>(settings); return new VowpalWabbitThreadedPrediction<TContext>(settings);
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<int[]> MapContext(VowpalWabbit<TContext> vw, TContext context) protected override PolicyDecision<int[]> MapContext(VowpalWabbit<TContext> vw, TContext context)
{ {
if (this.developmentMode) if (this.developmentMode)
@ -54,12 +68,19 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
return PolicyDecision.Create(actions, state); return PolicyDecision.Create(actions, state);
} }
/// <summary>
/// Returns the number of actions defined by this context.
/// </summary>
public int GetNumberOfActions(TContext context) public int GetNumberOfActions(TContext context)
{ {
return this.serializer.GetNumberOfActionDependentExamples(context); return this.serializer.GetNumberOfActionDependentExamples(context);
} }
} }
/// <summary>
/// Vowpal Wabbit based ranker using C# defined context and action dependent features.
/// </summary>
public class VWRanker<TContext, TActionDependentFeature> : public class VWRanker<TContext, TActionDependentFeature> :
VWBaseContextMapper<VowpalWabbit<TContext, TActionDependentFeature>, TContext, int[]>, VWBaseContextMapper<VowpalWabbit<TContext, TActionDependentFeature>, TContext, int[]>,
IRanker<TContext>, INumberOfActionsProvider<TContext> IRanker<TContext>, INumberOfActionsProvider<TContext>
@ -69,7 +90,6 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
/// <summary> /// <summary>
/// Constructor using a memory stream. /// Constructor using a memory stream.
/// </summary> /// </summary>
/// <param name="vwModelStream">The VW model memory stream.</param>
public VWRanker( public VWRanker(
Func<TContext, IReadOnlyCollection<TActionDependentFeature>> getContextFeaturesFunc, Func<TContext, IReadOnlyCollection<TActionDependentFeature>> getContextFeaturesFunc,
Stream vwModelStream = null, Stream vwModelStream = null,
@ -80,11 +100,22 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
this.getContextFeaturesFunc = getContextFeaturesFunc; this.getContextFeaturesFunc = getContextFeaturesFunc;
} }
/// <summary>
/// Sub classes must override and create a new VW pool.
/// </summary>
protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext, TActionDependentFeature>> CreatePool(VowpalWabbitSettings settings) protected override VowpalWabbitThreadedPredictionBase<VowpalWabbit<TContext, TActionDependentFeature>> CreatePool(VowpalWabbitSettings settings)
{ {
return new VowpalWabbitThreadedPrediction<TContext, TActionDependentFeature>(settings); return new VowpalWabbitThreadedPrediction<TContext, TActionDependentFeature>(settings);
} }
/// <summary>
/// Determines the action to take for a given context.
/// This implementation should be thread-safe if multithreading is needed.
/// </summary>
/// <param name="vw">The Vowpal Wabbit instance to use.</param>
/// <param name="context">A user-defined context for the decision.</param>
/// <returns>A decision tuple containing the index of the action to take (1-based), and the Id of the model or policy used to make the decision.
/// Can be null if the Policy is not ready yet (e.g. model not loaded).</returns>
protected override PolicyDecision<int[]> MapContext(VowpalWabbit<TContext, TActionDependentFeature> vw, TContext context) protected override PolicyDecision<int[]> MapContext(VowpalWabbit<TContext, TActionDependentFeature> vw, TContext context)
{ {
if (this.developmentMode) if (this.developmentMode)
@ -104,6 +135,9 @@ namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
return PolicyDecision.Create(actions, state); return PolicyDecision.Create(actions, state);
} }
/// <summary>
/// Returns the number of actions defined by this context.
/// </summary>
public int GetNumberOfActions(TContext context) public int GetNumberOfActions(TContext context)
{ {
var adfs = this.getContextFeaturesFunc(context); var adfs = this.getContextFeaturesFunc(context);

Просмотреть файл

@ -7,9 +7,15 @@ using System.Threading.Tasks;
namespace Microsoft.Research.MultiWorldTesting.ClientLibrary namespace Microsoft.Research.MultiWorldTesting.ClientLibrary
{ {
/// <summary>
/// Defines the policy state for a VowpalWabbit model.
/// </summary>
[JsonObject(Id = "stvw")] [JsonObject(Id = "stvw")]
public class VWState public class VWState
{ {
/// <summary>
/// The model id used at scoring time.
/// </summary>
[JsonProperty("m")] [JsonProperty("m")]
public string ModelId { get; set; } public string ModelId { get; set; }
} }

Просмотреть файл

@ -33,12 +33,17 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// </summary> /// </summary>
protected readonly BatchingConfiguration batchConfig; protected readonly BatchingConfiguration batchConfig;
private readonly CancellationTokenSource cancellationTokenSource; private readonly CancellationTokenSource cancellationTokenSource;
/// <summary>
/// Cancellation token used for shutdown
/// </summary>
protected CancellationToken cancellationToken; protected CancellationToken cancellationToken;
/// <summary> /// <summary>
/// Constructs an uploader object. /// Constructs an uploader object.
/// </summary> /// </summary>
/// <param name="batchConfig">Optional; The batching configuration that controls the buffer size.</param> /// <param name="batchConfig">Optional; The batching configuration that controls the buffer size.</param>
/// <param name="developmentMode">If true, enables additional logging and disables batching.</param>
public BaseEventUploader(BatchingConfiguration batchConfig = null, bool developmentMode = false) public BaseEventUploader(BatchingConfiguration batchConfig = null, bool developmentMode = false)
{ {
this.cancellationTokenSource = new CancellationTokenSource(); this.cancellationTokenSource = new CancellationTokenSource();
@ -96,6 +101,9 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// </summary> /// </summary>
public event EventUploaderSuccessEventHandler SuccessHandler; public event EventUploaderSuccessEventHandler SuccessHandler;
/// <summary>
/// Invoke when a batch completed.
/// </summary>
public event EventUploaderCompletedEventHandler CompletionHandler; public event EventUploaderCompletedEventHandler CompletionHandler;
internal void FireErrorHandler(Exception e) internal void FireErrorHandler(Exception e)

Просмотреть файл

@ -6,10 +6,19 @@ using System.Threading.Tasks.Dataflow;
namespace Microsoft.Research.MultiWorldTesting.JoinUploader namespace Microsoft.Research.MultiWorldTesting.JoinUploader
{ {
/// <summary>
/// Delegate definition for success.
/// </summary>
public delegate void EventUploaderSuccessEventHandler(object source, int eventCount, int sumSize, int inputQueueSize); public delegate void EventUploaderSuccessEventHandler(object source, int eventCount, int sumSize, int inputQueueSize);
/// <summary>
/// Delegate definition for error.
/// </summary>
public delegate void EventUploaderErrorEventHandler(object source, Exception e); public delegate void EventUploaderErrorEventHandler(object source, Exception e);
/// <summary>
/// Delegate definition for completion.
/// </summary>
public delegate void EventUploaderCompletedEventHandler(object source, string blockName, Task task); public delegate void EventUploaderCompletedEventHandler(object source, string blockName, Task task);
/// <summary> /// <summary>

Просмотреть файл

@ -48,6 +48,7 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// <param name="batchConfig">Optional; The batching configuration that controls the buffer size.</param> /// <param name="batchConfig">Optional; The batching configuration that controls the buffer size.</param>
/// <param name="loggingServiceBaseAddress">Optional; The address of a custom HTTP logging service. When null, the join service address is used.</param> /// <param name="loggingServiceBaseAddress">Optional; The address of a custom HTTP logging service. When null, the join service address is used.</param>
/// <param name="httpClient">Optional; The custom <see cref="IHttpClient"/> object to handle HTTP requests.</param> /// <param name="httpClient">Optional; The custom <see cref="IHttpClient"/> object to handle HTTP requests.</param>
/// <param name="developmentMode">If true, enables additional logging and disables batching.</param>
public EventUploader(BatchingConfiguration batchConfig = null, string loggingServiceBaseAddress = null, IHttpClient httpClient = null, bool developmentMode = false) public EventUploader(BatchingConfiguration batchConfig = null, string loggingServiceBaseAddress = null, IHttpClient httpClient = null, bool developmentMode = false)
: base(batchConfig, developmentMode) : base(batchConfig, developmentMode)
{ {

Просмотреть файл

@ -31,6 +31,7 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// </summary> /// </summary>
/// <param name="eventHubConnectionString">The Azure Stream Analytics connection string.</param> /// <param name="eventHubConnectionString">The Azure Stream Analytics connection string.</param>
/// <param name="batchConfig">Optional; The batching configuration to used when uploading data.</param> /// <param name="batchConfig">Optional; The batching configuration to used when uploading data.</param>
/// <param name="developmentMode">If true, enables additional logging and disables batching.</param>
public EventUploaderASA public EventUploaderASA
( (
string eventHubConnectionString, string eventHubConnectionString,
@ -126,7 +127,7 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// <summary> /// <summary>
/// Uploads a single event to EventHub asynchronously. /// Uploads a single event to EventHub asynchronously.
/// </summary> /// </summary>
/// <param name="events">The event to upload.</param> /// <param name="evt">The event to upload.</param>
/// <returns>A Task object.</returns> /// <returns>A Task object.</returns>
private Task UploadToEventHubAsync(EventData evt) private Task UploadToEventHubAsync(EventData evt)
{ {

Просмотреть файл

@ -30,17 +30,34 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// </summary> /// </summary>
public string Key { get; set; } public string Key { get; set; }
// int, int[] /// <summary>
/// The action or ranking (int, int[])
/// </summary>
public object Value { get; set; } public object Value { get; set; }
/// <summary>
/// The supplied context.
/// </summary>
public object Context { get; set; } public object Context { get; set; }
/// <summary>
/// The state of the explorer (e.g. model id to be able to correlate back).
/// </summary>
public object ExplorerState { get; set; } public object ExplorerState { get; set; }
/// <summary>
/// The state of the mapper (e.g. model id to be able to correlate back).
/// </summary>
public object MapperState { get; set; } public object MapperState { get; set; }
/// <summary>
/// If pipeline overflows, we drop stochastically.
/// </summary>
public float? ProbabilityOfDrop { get; set; } public float? ProbabilityOfDrop { get; set; }
/// <summary>
/// Create epsilon greedy interaction???
/// </summary>
public static Interaction CreateEpsilonGreedy<TContext>(string key, TContext context, int action, float probability) public static Interaction CreateEpsilonGreedy<TContext>(string key, TContext context, int action, float probability)
{ {
return Interaction.Create(key, context, action, new GenericExplorerState { Probability = probability }); return Interaction.Create(key, context, action, new GenericExplorerState { Probability = probability });

Просмотреть файл

@ -58,6 +58,9 @@ namespace Microsoft.Research.MultiWorldTesting.JoinUploader
/// </summary> /// </summary>
event EventUploaderSuccessEventHandler SuccessHandler; event EventUploaderSuccessEventHandler SuccessHandler;
/// <summary>
/// Invoked on pipeline completion.
/// </summary>
event EventUploaderCompletedEventHandler CompletionHandler; event EventUploaderCompletedEventHandler CompletionHandler;
} }
} }

Просмотреть файл

@ -8,18 +8,30 @@ using System.Threading.Tasks;
namespace Microsoft.Research.MultiWorldTesting.JoinUploader namespace Microsoft.Research.MultiWorldTesting.JoinUploader
{ {
/// <summary>
/// Custom JSON.NET serializer for interactions.
/// </summary>
public class InteractionJsonConverter : JsonConverter public class InteractionJsonConverter : JsonConverter
{ {
/// <summary>
/// True, if it's an interaction type.
/// </summary>
public override bool CanConvert(Type objectType) public override bool CanConvert(Type objectType)
{ {
return objectType == typeof(Interaction); return objectType == typeof(Interaction);
} }
/// <summary>
/// Not supported.
/// </summary>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
/// <summary>
/// Serializes the interaction.
/// </summary>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{ {
var v = value as Interaction; var v = value as Interaction;

Просмотреть файл

@ -6,18 +6,44 @@
namespace Microsoft.Research.MultiWorldTesting.Contract namespace Microsoft.Research.MultiWorldTesting.Contract
{ {
/// <summary>
/// Various blob and container blob names
/// </summary>
public class ApplicationBlobConstants public class ApplicationBlobConstants
{ {
// Model blobs /// <summary>
/// Container name for models.
/// </summary>
public const string ModelContainerName = "mwt-models"; public const string ModelContainerName = "mwt-models";
/// <summary>
/// Blob name for latest model.
/// </summary>
public const string LatestModelBlobName = "current"; public const string LatestModelBlobName = "current";
// Settings blobs /// <summary>
/// Container name for settings.
/// </summary>
public const string SettingsContainerName = "mwt-settings"; public const string SettingsContainerName = "mwt-settings";
/// <summary>
/// Blob name for client settings.
/// </summary>
public const string LatestClientSettingsBlobName = "client"; public const string LatestClientSettingsBlobName = "client";
/// <summary>
/// Blob name for trainer settings.
/// </summary>
public const string LatestTrainerSettingsBlobName = "trainer"; public const string LatestTrainerSettingsBlobName = "trainer";
/// <summary>
/// Blob name for extra settings.
/// </summary>
public const string LatestExtraSettingsBlobName = "extra"; public const string LatestExtraSettingsBlobName = "extra";
/// <summary>
/// Container name for offline evaluation.
/// </summary>
public const string OfflineEvalContainerName = "mwt-offline-eval"; public const string OfflineEvalContainerName = "mwt-offline-eval";
} }
} }

Просмотреть файл

@ -5,8 +5,14 @@ using System.Net;
namespace Microsoft.Research.MultiWorldTesting.Contract namespace Microsoft.Research.MultiWorldTesting.Contract
{ {
/// <summary>
/// Helper class to download meta data.
/// </summary>
public static class ApplicationMetadataUtil public static class ApplicationMetadataUtil
{ {
/// <summary>
/// Download and deserialize settings.
/// </summary>
public static TMetadata DownloadMetadata<TMetadata>(string blobUri) public static TMetadata DownloadMetadata<TMetadata>(string blobUri)
{ {
string jsonMetadata = ""; string jsonMetadata = "";

Просмотреть файл

@ -6,8 +6,14 @@
namespace Microsoft.Research.MultiWorldTesting.Contract namespace Microsoft.Research.MultiWorldTesting.Contract
{ {
/// <summary>
/// Unused class.
/// </summary>
public class ApplicationSettingConstants public class ApplicationSettingConstants
{ {
/// <summary>
/// Unused.
/// </summary>
public const string UseLatestModelSetting = "latest"; public const string UseLatestModelSetting = "latest";
} }
} }

Просмотреть файл

@ -27,10 +27,20 @@ namespace Microsoft.Research.MultiWorldTesting.Contract
/// </summary> /// </summary>
public enum TrainFrequency public enum TrainFrequency
{ {
/// <summary>
/// Low frequency.
/// </summary>
Low = 0, Low = 0,
/// <summary>
/// High frequency.
/// </summary>
High High
} }
/// <summary>
/// Defines the content of the client settings file.
/// </summary>
public class ApplicationClientMetadata public class ApplicationClientMetadata
{ {
/// <summary> /// <summary>
@ -68,9 +78,15 @@ namespace Microsoft.Research.MultiWorldTesting.Contract
/// </summary> /// </summary>
public string AppInsightsKey { get; set; } public string AppInsightsKey { get; set; }
/// <summary>
/// Amount of exploration to apply if no model is available yet.
/// </summary>
public float InitialExplorationEpsilon { get; set; } public float InitialExplorationEpsilon { get; set; }
} }
/// <summary>
/// Defines the content of the "extra" settings file.
/// </summary>
public class ApplicationExtraMetadata public class ApplicationExtraMetadata
{ {
/// <summary> /// <summary>

Просмотреть файл

@ -6,15 +6,39 @@
namespace Microsoft.Research.MultiWorldTesting.Contract namespace Microsoft.Research.MultiWorldTesting.Contract
{ {
/// <summary>
/// Service constants used for old join service.
/// </summary>
public class ServiceConstants public class ServiceConstants
{ {
// Join Server /// <summary>
/// public address of join server.
/// </summary>
public const string JoinAddress = "http://decisionservice.cloudapp.net"; public const string JoinAddress = "http://decisionservice.cloudapp.net";
/// <summary>
/// Path for joining.
/// </summary>
public const string JoinPostAddress = "/join"; public const string JoinPostAddress = "/join";
/// <summary>
/// Authentication header.
/// </summary>
public const string TokenAuthenticationScheme = "Bearer"; public const string TokenAuthenticationScheme = "Bearer";
/// <summary>
/// Authentication scheme.
/// </summary>
public const string ConnectionStringAuthenticationScheme = "AzureStorage"; public const string ConnectionStringAuthenticationScheme = "AzureStorage";
/// <summary>
/// Azure container name.
/// </summary>
public const string IncompleteContainerPrefix = "incomplete"; public const string IncompleteContainerPrefix = "incomplete";
/// <summary>
/// Azure container name.
/// </summary>
public const string JoinedBlobContainerPrefix = "joined-examples"; public const string JoinedBlobContainerPrefix = "joined-examples";
} }
} }