/// <summary> /// Executes a query to Kusto for Fields Caps. /// </summary> /// <param name="indexName">Index name.</param> /// <returns>An object with the field caps.</returns> public async Task <FieldCapabilityResponse> GetFieldCapsAsync(string indexName) { var response = new FieldCapabilityResponse(); try { Logger.LogDebug("Getting schema for table '{@indexName}'", indexName); var(databaseName, tableName) = KustoDatabaseTableNames.FromElasticIndexName(indexName, Kusto.DefaultDatabaseName); string kustoCommand = $".show {KustoQLOperators.Databases} {KustoQLOperators.Schema} | {KustoQLOperators.Where} TableName=='{tableName}' {KustoQLOperators.And} DatabaseName=='{databaseName}' {KustoQLOperators.And} ColumnName!='' | {KustoQLOperators.Project} ColumnName, ColumnType"; using IDataReader kustoResults = await Kusto.ExecuteControlCommandAsync(kustoCommand, RequestContext); MapFieldCaps(kustoResults, response); if (response.Fields.Count > 0) { return(response); } Logger.LogDebug("Getting schema for function '{@indexName}'", indexName); string functionQuery = $"{tableName} | {KustoQLOperators.GetSchema} | project ColumnName, ColumnType=DataType"; var functionQueryData = new QueryData(functionQuery, tableName, null, null); var(timeTaken, reader) = await Kusto.ExecuteQueryAsync(functionQueryData, RequestContext); MapFieldCaps(reader, response); } catch (Exception ex) { Logger.LogError(ex, "Error while executing GetFieldCaps."); throw; } return(response); }
/// <summary> /// Executes a query to Kusto for Index List. /// Searches for all tables and all functions that match the index name pattern. /// </summary> /// <param name="indexName">Index name pattern, e.g. "*", "orders*", "orders".</param> /// <returns>A list of Indexes matching the given name pattern.</returns> public async Task <IndexListResponseElement> GetIndexListAsync(string indexName) { var response = new IndexListResponseElement(); try { Logger.LogDebug("Listing tables matching '{@indexName}'", indexName); var(databaseName, tableName) = KustoDatabaseTableNames.FromElasticIndexName(indexName, Kusto.DefaultDatabaseName); string readTablesCommand = $".show {KustoQLOperators.Databases} {KustoQLOperators.Schema} | {KustoQLOperators.Where} TableName != '' | {KustoQLOperators.Distinct} TableName, DatabaseName | {KustoQLOperators.Search} TableName: '{tableName}' | {KustoQLOperators.Search} DatabaseName: '{databaseName}' | {KustoQLOperators.Project} strcat(DatabaseName, \"{KustoDatabaseTableNames.Separator}\", TableName)"; using IDataReader kustoTables = await Kusto.ExecuteControlCommandAsync(readTablesCommand, RequestContext); if (kustoTables != null) { MapIndexList(kustoTables, response); } Logger.LogDebug("Listing functions matching '{@indexName}'", indexName); var defaultDb = Kusto.DefaultDatabaseName; string readFunctionsCommand = $".show {KustoQLOperators.Functions} | {KustoQLOperators.Where} Parameters == '()' | {KustoQLOperators.Distinct} Name | {KustoQLOperators.Search} Name: '{tableName}' | {KustoQLOperators.Project} strcat(\"{defaultDb}\", \"{KustoDatabaseTableNames.Separator}\", Name)"; using IDataReader kustoFunctions = await Kusto.ExecuteControlCommandAsync(readFunctionsCommand, RequestContext); if (kustoFunctions != null) { MapIndexList(kustoFunctions, response); } } catch (Exception ex) { Logger.LogError(ex, "Error while executing GetIndexList."); throw; } return(response); }
/// <inheritdoc/> public void Visit(ElasticSearchDSL elasticSearchDSL) { Ensure.IsNotNull(elasticSearchDSL, nameof(elasticSearchDSL)); // Preparing the schema with the index name to be used later schemaRetriever = schemaRetrieverFactory.Make(elasticSearchDSL.IndexName); // base query elasticSearchDSL.Query.Accept(this); var queryStringBuilder = new StringBuilder(); var(databaseName, tableName) = KustoDatabaseTableNames.FromElasticIndexName(elasticSearchDSL.IndexName, defaultDatabaseName); // when an index-pattern doesn't have a default time filter the query element can be empty var translatedQueryExpression = !string.IsNullOrEmpty(elasticSearchDSL.Query.KustoQL) ? $"| {elasticSearchDSL.Query.KustoQL}" : string.Empty; // Aggregations if (elasticSearchDSL.Query.Bool != null) { queryStringBuilder.Append($"{KustoQLOperators.Let} _data = database(\"{databaseName}\").{tableName} {translatedQueryExpression};"); // Aggregations if (elasticSearchDSL.Aggregations?.Count > 0) { queryStringBuilder.Append('\n').Append($"(_data | {KustoQLOperators.Summarize} "); foreach (var(_, aggregation) in elasticSearchDSL.Aggregations) { aggregation.Accept(this); queryStringBuilder.Append($"{aggregation.KustoQL} "); } queryStringBuilder.Append("| as aggs);"); } // hits (projections...) // The size is deserialized property // therefore we check 'Size >= 0' to protect the query. if (elasticSearchDSL.Size >= 0) { queryStringBuilder.Append("\n(_data "); if (elasticSearchDSL.Size > 0) { // we only need to sort if we're returning hits var orderingList = new List <string>(); foreach (var sortClause in elasticSearchDSL.Sort) { sortClause.Accept(this); if (!string.IsNullOrEmpty(sortClause.KustoQL)) { orderingList.Add(sortClause.KustoQL); } } if (orderingList.Count > 0) { queryStringBuilder.Append($"| {KustoQLOperators.OrderBy} {string.Join(", ", orderingList)} "); } } queryStringBuilder.Append($"| {KustoQLOperators.Limit} {elasticSearchDSL.Size} | as hits)"); } } else { // ViewSingleDocument query queryStringBuilder.Append($"database(\"{databaseName}\").{tableName} {translatedQueryExpression} | as hits;"); } elasticSearchDSL.KustoQL = queryStringBuilder.ToString(); }