Kusto Sorguları için Örnekler
Bu makalede, yaygın sorgular ve bunları karşılamak için Kusto Sorgu Dili nasıl kullanabileceğiniz tanımlanır.
Sütun grafiği görüntüleme
İki veya daha fazla sütunu yansıtmak ve sonra sütunları grafiğin x ekseni ve y ekseni olarak kullanmak için:
StormEvents
| where isnotempty(EndLocation)
| summarize event_count=count() by EndLocation
| top 10 by event_count
| render columnchart
- İlk sütun x eksenini oluşturur. Sayısal, tarih-saat veya dize olabilir.
- Görüntülediğiniz veri hacmini sınırlamak için ,
summarize
vetop
kullanınwhere
. - X ekseninin sırasını tanımlamak için sonuçları sıralayın.
Başlangıç ve durdurma olaylarından oturum alma
Bir olay günlüğünde, bazı olaylar genişletilmiş etkinliğin veya oturumun başlangıcını veya sonunu işaretler.
Name | Şehir | SessionId | Zaman damgası |
---|---|---|---|
Başlangıç | Londra | 2817330 | 2015-12-09T10:12:02.32 |
Game | Londra | 2817330 | 2015-12-09T10:12:52.45 |
Başlangıç | Manchester | 4267667 | 2015-12-09T10:14:02.23 |
Durdur | Londra | 2817330 | 2015-12-09T10:23:43.18 |
İptal | Manchester | 4267667 | 2015-12-09T10:27:26.29 |
Durdur | Manchester | 4267667 | 2015-12-09T10:28:31.72 |
Her olayın bir oturum kimliği (SessionId
) vardır. Sınama, başlatma ve durdurma olaylarını bir oturum kimliğiyle eşleştirmektir.
Örnek:
let Events = MyLogTable | where ... ;
Events
| where Name == "Start"
| project Name, City, SessionId, StartTime=timestamp
| join (Events
| where Name == "Stop"
| project StopTime=timestamp, SessionId)
on SessionId
| project City, SessionId, StartTime, StopTime, Duration = StopTime - StartTime
Başlatma ve durdurma olaylarını oturum kimliğiyle eşleştirmek için:
- Birleştirmeye başlamadan önce mümkün olduğunca aşağı doğru ayrıştırılan tablonun projeksiyonunu adlandırmak için let komutunu kullanın.
- Zaman damgalarının adlarını hem başlangıç saati hem de durdurma zamanı sonuçlarda görünecek şekilde değiştirmek için project kullanın.
project
ayrıca sonuçlarda görüntülemek üzere diğer sütunları seçer. - Aynı etkinliğin başlangıç ve durdurma girdileriyle eşleştirmek için birleştirmeyi kullanın. Her etkinlik için bir satır oluşturulur.
- Etkinliğin süresini göstermek üzere bir sütun eklemek için yeniden kullanın
project
.
Çıktı aşağıda verilmiştir:
Şehir | SessionId | StartTime | Stoptime | Süre |
---|---|---|---|---|
Londra | 2817330 | 2015-12-09T10:12:02.32 | 2015-12-09T10:23:43.18 | 00:11:40.46 |
Manchester | 4267667 | 2015-12-09T10:14:02.23 | 2015-12-09T10:28:31.72 | 00:14:29.49 |
Oturum kimliği kullanmadan oturum alma
Başlangıç ve durdurma olaylarının kolayca eşleştirebileceğimiz bir oturum kimliğine sahip olmadığını varsayalım. Ancak, oturumun gerçekleştiği istemcinin IP adresine sahibiz. Her istemci adresinin aynı anda yalnızca bir oturum yürüttüğü varsayıldığında, her başlangıç olayını aynı IP adresinden bir sonraki durdurma olayıyla eşleştirebiliriz:
Örnek:
Events
| where Name == "Start"
| project City, ClientIp, StartTime = timestamp
| join kind=inner
(Events
| where Name == "Stop"
| project StopTime = timestamp, ClientIp)
on ClientIp
| extend duration = StopTime - StartTime
// Remove matches with earlier stops:
| where duration > 0
// Pick out the earliest stop for each start and client:
| summarize arg_min(duration, *) by bin(StartTime,1s), ClientIp
Her join
başlangıç saatini aynı istemci IP adresinden gelen tüm durdurma zamanlarıyla eşleştirir. Örnek kod:
- Önceki durdurma süreleriyle eşleşmeleri kaldırır.
- Her oturum için bir grup almak için başlangıç zamanına ve IP adresine göre gruplar.
- parametresi için
StartTime
birbin
işlev sağlar. Bu adımı gerçekleştirmezseniz Kusto, bazı başlangıç saatleriyle yanlış durdurma zamanlarıyla eşleşen bir saatlik bölmeleri otomatik olarak kullanır.
arg_min
her gruptaki en küçük süreye sahip satırı bulur ve *
parametresi diğer tüm sütunlardan geçer.
Bağımsız değişken her sütun adına ön ek ekler min_
.
Uygun boyuttaki bölmelerde süreleri saymak için kod ekleyin. Bu örnekte, çubuk grafiğin tercihi nedeniyle, zaman çizelgelerini sayılara dönüştürmek için ölçütüne bölün 1s
:
// Count the frequency of each duration:
| summarize count() by duration=bin(min_duration/1s, 10)
// Cut off the long tail:
| where duration < 300
// Display in a bar chart:
| sort by duration asc | render barchart
Tam örnek
Logs
| where ActivityId == "ActivityId with Blablabla"
| summarize max(Timestamp), min(Timestamp)
| extend Duration = max_Timestamp - min_Timestamp
wabitrace
| where Timestamp >= datetime(2015-01-12 11:00:00Z)
| where Timestamp < datetime(2015-01-12 13:00:00Z)
| where EventText like "NotifyHadoopApplicationJobPerformanceCounters"
| extend Tenant = extract("tenantName=([^,]+),", 1, EventText)
| extend Environment = extract("environmentName=([^,]+),", 1, EventText)
| extend UnitOfWorkId = extract("unitOfWorkId=([^,]+),", 1, EventText)
| extend TotalLaunchedMaps = extract("totalLaunchedMaps=([^,]+),", 1, EventText, typeof(real))
| extend MapsSeconds = extract("mapsMilliseconds=([^,]+),", 1, EventText, typeof(real)) / 1000
| extend TotalMapsSeconds = MapsSeconds / TotalLaunchedMaps
| where Tenant == 'DevDiv' and Environment == 'RollupDev2'
| where TotalLaunchedMaps > 0
| summarize sum(TotalMapsSeconds) by UnitOfWorkId
| extend JobMapsSeconds = sum_TotalMapsSeconds * 1
| project UnitOfWorkId, JobMapsSeconds
| join (
wabitrace
| where Timestamp >= datetime(2015-01-12 11:00:00Z)
| where Timestamp < datetime(2015-01-12 13:00:00Z)
| where EventText like "NotifyHadoopApplicationJobPerformanceCounters"
| extend Tenant = extract("tenantName=([^,]+),", 1, EventText)
| extend Environment = extract("environmentName=([^,]+),", 1, EventText)
| extend UnitOfWorkId = extract("unitOfWorkId=([^,]+),", 1, EventText)
| extend TotalLaunchedReducers = extract("totalLaunchedReducers=([^,]+),", 1, EventText, typeof(real))
| extend ReducesSeconds = extract("reducesMilliseconds=([^,]+)", 1, EventText, typeof(real)) / 1000
| extend TotalReducesSeconds = ReducesSeconds / TotalLaunchedReducers
| where Tenant == 'DevDiv' and Environment == 'RollupDev2'
| where TotalLaunchedReducers > 0
| summarize sum(TotalReducesSeconds) by UnitOfWorkId
| extend JobReducesSeconds = sum_TotalReducesSeconds * 1
| project UnitOfWorkId, JobReducesSeconds )
on UnitOfWorkId
| join (
wabitrace
| where Timestamp >= datetime(2015-01-12 11:00:00Z)
| where Timestamp < datetime(2015-01-12 13:00:00Z)
| where EventText like "NotifyHadoopApplicationJobPerformanceCounters"
| extend Tenant = extract("tenantName=([^,]+),", 1, EventText)
| extend Environment = extract("environmentName=([^,]+),", 1, EventText)
| extend JobName = extract("jobName=([^,]+),", 1, EventText)
| extend StepName = extract("stepName=([^,]+),", 1, EventText)
| extend UnitOfWorkId = extract("unitOfWorkId=([^,]+),", 1, EventText)
| extend LaunchTime = extract("launchTime=([^,]+),", 1, EventText, typeof(datetime))
| extend FinishTime = extract("finishTime=([^,]+),", 1, EventText, typeof(datetime))
| extend TotalLaunchedMaps = extract("totalLaunchedMaps=([^,]+),", 1, EventText, typeof(real))
| extend TotalLaunchedReducers = extract("totalLaunchedReducers=([^,]+),", 1, EventText, typeof(real))
| extend MapsSeconds = extract("mapsMilliseconds=([^,]+),", 1, EventText, typeof(real)) / 1000
| extend ReducesSeconds = extract("reducesMilliseconds=([^,]+)", 1, EventText, typeof(real)) / 1000
| extend TotalMapsSeconds = MapsSeconds / TotalLaunchedMaps
| extend TotalReducesSeconds = (ReducesSeconds / TotalLaunchedReducers / ReducesSeconds) * ReducesSeconds
| extend CalculatedDuration = (TotalMapsSeconds + TotalReducesSeconds) * time(1s)
| where Tenant == 'DevDiv' and Environment == 'RollupDev2')
on UnitOfWorkId
| extend MapsFactor = TotalMapsSeconds / JobMapsSeconds
| extend ReducesFactor = TotalReducesSeconds / JobReducesSeconds
| extend CurrentLoad = 1536 + (768 * TotalLaunchedMaps) + (1536 * TotalLaunchedMaps)
| extend NormalizedLoad = 1536 + (768 * TotalLaunchedMaps * MapsFactor) + (1536 * TotalLaunchedMaps * ReducesFactor)
| summarize sum(CurrentLoad), sum(NormalizedLoad) by JobName
| extend SaveFactor = sum_NormalizedLoad / sum_CurrentLoad
Zaman içindeki eş zamanlı oturumları grafiği oluşturma
Bir etkinlik tablonuz olduğunu ve bunların başlangıç ve bitiş saatlerine sahip olduğunuzu varsayalım. Zaman içinde eşzamanlı olarak çalıştırılacak etkinlik sayısını gösteren bir grafik gösterebilirsiniz.
Aşağıda adlı X
bir örnek giriş verilmişti:
SessionId | StartTime | Stoptime |
---|---|---|
a | 10:01:03 | 10:10:08 |
b | 10:01:29 | 10:03:10 |
c | 10:03:02 | 10:05:20 |
Bir dakikalık bölmelerdeki bir grafik için, her bir dakikalık aralıkta çalışan her etkinliği saymak istiyorsunuz.
Ara bir sonuç aşağıdadır:
X | extend samples = range(bin(StartTime, 1m), StopTime, 1m)
range
belirtilen aralıklarda bir değer dizisi oluşturur:
SessionId | StartTime | Stoptime | Örnekleri |
---|---|---|---|
a | 10:01:33 | 10:06:31 | [10:01:00,10:02:00,... 10:06:00] |
b | 10:02:29 | 10:03:45 | [10:02:00,10:03:00] |
c | 10:03:12 | 10:04:30 | [10:03:00,10:04:00] |
Bu dizileri tutmak yerine mv-expand kullanarak genişletin:
X | mv-expand samples = range(bin(StartTime, 1m), StopTime , 1m)
Çıkış
SessionId | StartTime | Stoptime | Örnekleri |
---|---|---|---|
a | 10:01:33 | 10:06:31 | 10:01:00 |
a | 10:01:33 | 10:06:31 | 10:02:00 |
a | 10:01:33 | 10:06:31 | 10:03:00 |
a | 10:01:33 | 10:06:31 | 10:04:00 |
a | 10:01:33 | 10:06:31 | 10:05:00 |
a | 10:01:33 | 10:06:31 | 10:06:00 |
b | 10:02:29 | 10:03:45 | 10:02:00 |
b | 10:02:29 | 10:03:45 | 10:03:00 |
c | 10:03:12 | 10:04:30 | 10:03:00 |
c | 10:03:12 | 10:04:30 | 10:04:00 |
Şimdi, sonuçları örnek zamana göre gruplandırın ve her etkinliğin oluşumlarını sayın:
X
| mv-expand samples = range(bin(StartTime, 1m), StopTime , 1m)
| summarize count_SessionId = count() by bin(todatetime(samples),1m)
- mv-expand, dinamik türdeki bir sütunda sonuçladığı için kullanın
todatetime()
. - Kullanın
bin()
çünkü sayısal değerler ve tarihler için aralık belirtmezseniz varsayılansummarize
aralığı kullanarak her zaman birbin()
işlev uygular.
Çıktı aşağıda verilmiştir:
count_SessionId | Örnekleri |
---|---|
1 | 10:01:00 |
2 | 10:02:00 |
3 | 10:03:00 |
2 | 10:04:00 |
1 | 10:05:00 |
1 | 10:06:00 |
Sonuçları işlemek için çubuk grafik veya zaman çizelgesi kullanabilirsiniz.
Özetlemek için null bölmeler ekleme
summarize
İşleç, tarih-saat sütunundan oluşan bir grup anahtarına uygulandığında, bu değerleri sabit genişlikli bölmelere bindirin:
let StartTime=ago(12h);
let StopTime=now()
T
| where Timestamp > StartTime and Timestamp <= StopTime
| where ...
| summarize Count=count() by bin(Timestamp, 5m)
Bu örnek, beş dakikalık her bölmeye giren satır grubu başına tek bir satırı T
olan bir tablo oluşturur.
Kodun gerçekleştirmediği şey , ile arasında StartTime
StopTime
karşılık gelen satır T
bulunmayan zaman bölmesi değerleri için "null bölmeler" (satırlar) eklemektir. Masayı bu bölmelerle "doldurmak" iyi bir fikirdir. Bunu şu şekilde yapabilirsiniz:
let StartTime=ago(12h);
let StopTime=now()
T
| where Timestamp > StartTime and Timestamp <= StopTime
| summarize Count=count() by bin(Timestamp, 5m)
| where ...
| union ( // 1
range x from 1 to 1 step 1 // 2
| mv-expand Timestamp=range(StartTime, StopTime, 5m) to typeof(datetime) // 3
| extend Count=0 // 4
)
| summarize Count=sum(Count) by bin(Timestamp, 5m) // 5
Önceki sorgunun adım adım açıklaması aşağıdadır:
- Tabloya
union
daha fazla satır eklemek için işlecini kullanın. Bu satırlar ifade tarafındanunion
oluşturulur. - işleci,
range
tek satır ve sütuna sahip bir tablo oluşturur. Tablo üzerinde çalışmak dışında hiçbir şey içinmv-expand
kullanılmaz. mv-expand
işlevininrange
üzerindeki işleç, ileEndTime
arasındaStartTime
beş dakikalık bölmeler olduğu kadar çok satır oluşturur.- bir
Count
kullanın0
. summarize
işleci, özgün (sol veya dış) bağımsız değişkendeki bölmeleri ile gruplandırıyorunion
. İşleç ayrıca iç bağımsız değişkenden buna bölmeler (null bölme satırları). Bu işlem, çıkışın depo gözü başına değeri sıfır veya özgün sayı olan bir satırı olmasını sağlar.
Makine öğrenmesi ile Kusto kullanarak verilerinizden daha fazlasını elde edin
Birçok ilginç kullanım örneği makine öğrenmesi algoritmalarını kullanır ve telemetri verilerinden ilginç içgörüler elde eder. Bu algoritmalar genellikle giriş olarak kesin olarak yapılandırılmış bir veri kümesi gerektirir. Ham günlük verileri genellikle gerekli yapı ve boyutla eşleşmiyor.
Belirli bir Bing çıkarımları hizmetinin hata oranındaki anomalileri arayarak başlayın. Günlükler tablosunda 65 milyar kayıt var. Aşağıdaki temel sorgu 250.000 hatayı filtreler ve ardından series_decompose_anomalies anomali algılama işlevini kullanan bir hata sayısı zaman serisi oluşturur. Anomaliler Kusto hizmeti tarafından algılanır ve zaman serisi grafiğinde kırmızı noktalar olarak vurgulanır.
Logs
| where Timestamp >= datetime(2015-08-22) and Timestamp < datetime(2015-08-23)
| where Level == "e" and Service == "Inferences.UnusualEvents_Main"
| summarize count() by bin(Timestamp, 5min)
| render anomalychart
Hizmet, şüpheli hata oranlarına sahip birkaç zaman demeti tanımladı. Bu zaman dilimini yakınlaştırmak için Kusto kullanın. Ardından, sütunda Message
toplayan bir sorgu çalıştırın. En çok karşılaşılan hataları bulmayı deneyin.
İletinin tüm yığın izlemesinin ilgili bölümleri kırpılır, böylece sonuçlar sayfaya daha iyi sığar.
İlk sekiz hatanın başarılı bir şekilde tanımlanmasını görebilirsiniz. Ancak, hata iletisi değişen verileri içeren bir biçim dizesi kullanılarak oluşturulduğundan, sonraki uzun bir hata serisidir:
Logs
| where Timestamp >= datetime(2015-08-22 05:00) and Timestamp < datetime(2015-08-22 06:00)
| where Level == "e" and Service == "Inferences.UnusualEvents_Main"
| summarize count() by Message
| top 10 by count_
| project count_, Message
Çıkış
Sayısı_ | Message |
---|---|
7125 | 'RunCycleFromInterimData' yöntemi için ExecuteAlgorithmMethod başarısız oldu... |
7125 | InferenceHostService çağrısı başarısız oldu.. System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı... |
7124 | Beklenmeyen Çıkarım Sistemi hatası.. System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı... |
5112 | Beklenmeyen Çıkarım Sistemi hatası.. System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı.. |
174 | InferenceHostService çağrısı başarısız oldu.. System.ServiceModel.CommunicationException: Kanala yazılırken bir hata oluştu:... |
10 | 'RunCycleFromInterimData' yöntemi için ExecuteAlgorithmMethod başarısız oldu... |
10 | Çıkarım Sistemi hatası.. Microsoft.Bing.Platform.Inferences.Service.Managers.UserInterimDataManagerException:... |
3 | InferenceHostService çağrısı başarısız oldu.. System.ServiceModel.CommunicationObjectFaultedException:... |
1 | Çıkarım Sistemi hatası... SocialGraph.BOSS.OperationResponse... AIS TraceId:8292FC561AC64BED8FA243808FE74EFD... |
1 | Çıkarım Sistemi hatası... SocialGraph.BOSS.OperationResponse... AIS TraceId: 5F79F7587FF943EC9B641E02E701AFBF... |
Bu noktada işlecini reduce
kullanmak yardımcı olur. işleci, koddaki aynı izleme izleme noktasından kaynaklanan 63 farklı hata tanımladı. reduce
bu zaman penceresindeki ek anlamlı hata izlemelerine odaklanmaya yardımcı olur.
Logs
| where Timestamp >= datetime(2015-08-22 05:00) and Timestamp < datetime(2015-08-22 06:00)
| where Level == "e" and Service == "Inferences.UnusualEvents_Main"
| reduce by Message with threshold=0.35
| project Count, Pattern
Çıkış
Count | Desen |
---|---|
7125 | 'RunCycleFromInterimData' yöntemi için ExecuteAlgorithmMethod başarısız oldu... |
7125 | InferenceHostService çağrısı başarısız oldu.. System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı... |
7124 | Beklenmeyen Çıkarım Sistemi hatası.. System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı... |
5112 | Beklenmeyen Çıkarım Sistemi hatası.. System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı... |
174 | InferenceHostService çağrısı başarısız oldu.. System.ServiceModel.CommunicationException: Kanala yazılırken bir hata oluştu:... |
63 | Çıkarım Sistemi hatası.. Microsoft.Bing.Platform.Inferences.*: Object BOSS'a yazmak için * yazın.*: SocialGraph.BOSS.Reques... |
10 | 'RunCycleFromInterimData' yöntemi için ExecuteAlgorithmMethod başarısız oldu... |
10 | Çıkarım Sistemi hatası.. Microsoft.Bing.Platform.Inferences.Service.Managers.UserInterimDataManagerException:... |
3 | InferenceHostService çağrısı başarısız oldu.. System.ServiceModel.*: ** için System.ServiceModel.Channels.*+*nesnesi *... syst... |
Şimdi, algılanan anomalilere katkıda bulunan en önemli hataların iyi bir görünümüne sahipsiniz.
Bu hataların örnek sistem üzerindeki etkisini anlamak için şunları göz önünde bulundurun:
- Tabloda
Logs
veCluster
gibiComponent
ek boyutlu veriler bulunur. - Yeni otomatik küme eklentisi, basit bir sorguyla bileşen ve küme içgörülerini türetebilirsiniz.
Aşağıdaki örnekte, ilk dört hatanın her birinin bir bileşene özgü olduğunu açıkça görebilirsiniz. Ayrıca, ilk üç hata DB4 kümesine özgü olsa da, dördüncü hata tüm kümelerde gerçekleşir.
Logs
| where Timestamp >= datetime(2015-08-22 05:00) and Timestamp < datetime(2015-08-22 06:00)
| where Level == "e" and Service == "Inferences.UnusualEvents_Main"
| evaluate autocluster()
Çıkış
Count | Yüzde (%) | Bileşen | Küme | Message |
---|---|---|---|---|
7125 | 26.64 | InferenceHostService | DB4 | ExecuteAlgorithmMethod for method... |
7125 | 26.64 | Bilinmeyen Bileşen | DB4 | InferenceHostService çağrısı başarısız oldu... |
7124 | 26.64 | InferenceAlgorithmExecutor | DB4 | Beklenmeyen Çıkarım Sistemi hatası... |
5112 | 19.11 | InferenceAlgorithmExecutor | * | Beklenmeyen Çıkarım Sistemi hatası... |
Değerleri bir kümeden diğerine eşleme
Yaygın bir sorgu kullanım örneği, değerlerin statik eşlemesidir. Statik eşleme, sonuçların daha sunulu hale getirilebilir hale getirmesini sağlayabilir.
Örneğin, sonraki tabloda DeviceModel
bir cihaz modeli belirtir. Cihaz modelini kullanmak, cihaz adına başvurmak için uygun bir biçim değildir.
DeviceModel | Count |
---|---|
iPhone5,1 | 32 |
iPhone3,2 | 432 |
iPhone7,2 | 55 |
iPhone5,2 | 66 |
Kolay ad kullanmak daha kullanışlıdır:
Friendlyname | Count |
---|---|
iPhone 5 | 32 |
iPhone 4 | 432 |
iPhone 6 | 55 |
iPhone5 | 66 |
Sonraki iki örnek, bir cihazı tanımlamak için cihaz modeli kullanmaktan kolay bir ada nasıl değiştireceğini gösterir.
Dinamik sözlük kullanarak eşleme
Bir dinamik sözlük ve dinamik erişimciler kullanarak eşleme gerçekleştirebilirsiniz. Örneğin:
// Dataset definition
let Source = datatable(DeviceModel:string, Count:long)
[
'iPhone5,1', 32,
'iPhone3,2', 432,
'iPhone7,2', 55,
'iPhone5,2', 66,
];
// Query start here
let phone_mapping = dynamic(
{
"iPhone5,1" : "iPhone 5",
"iPhone3,2" : "iPhone 4",
"iPhone7,2" : "iPhone 6",
"iPhone5,2" : "iPhone5"
});
Source
| project FriendlyName = phone_mapping[DeviceModel], Count
Çıkış
Friendlyname | Count |
---|---|
iPhone 5 | 32 |
iPhone 4 | 432 |
iPhone 6 | 55 |
iPhone5 | 66 |
Statik tablo kullanarak eşleme
Ayrıca, kalıcı bir tablo ve join
işleç kullanarak da eşleme gerçekleştirebilirsiniz.
Eşleme tablosunu yalnızca bir kez oluşturun:
.create table Devices (DeviceModel: string, FriendlyName: string) .ingest inline into table Devices ["iPhone5,1","iPhone 5"]["iPhone3,2","iPhone 4"]["iPhone7,2","iPhone 6"]["iPhone5,2","iPhone5"]
Cihaz içeriğinin tablosunu oluşturun:
DeviceModel Friendlyname iPhone5,1 iPhone 5 iPhone3,2 iPhone 4 iPhone7,2 iPhone 6 iPhone5,2 iPhone5 Test tablosu kaynağı oluşturma:
.create table Source (DeviceModel: string, Count: int) .ingest inline into table Source ["iPhone5,1",32]["iPhone3,2",432]["iPhone7,2",55]["iPhone5,2",66]
Tabloları birleştirin ve projeyi çalıştırın:
Devices | join (Source) on DeviceModel | project FriendlyName, Count
Çıktı aşağıda verilmiştir:
Friendlyname | Count |
---|---|
iPhone 5 | 32 |
iPhone 4 | 432 |
iPhone 6 | 55 |
iPhone5 | 66 |
Sorgu zamanı boyut tabloları oluşturma ve kullanma
Genellikle sorgunun sonuçlarını veritabanında depolanmayan geçici bir boyut tablosuyla birleştirmek istersiniz. Sonucu tek bir sorgu kapsamına alınmış bir tablo olan bir ifade tanımlayabilirsiniz.
Örneğin:
// Create a query-time dimension table using datatable
let DimTable = datatable(EventType:string, Code:string)
[
"Heavy Rain", "HR",
"Tornado", "T"
]
;
DimTable
| join StormEvents on EventType
| summarize count() by Code
Aşağıda biraz daha karmaşık bir örnek verilmiştir:
// Create a query-time dimension table using datatable
let TeamFoundationJobResult = datatable(Result:int, ResultString:string)
[
-1, 'None', 0, 'Succeeded', 1, 'PartiallySucceeded', 2, 'Failed',
3, 'Stopped', 4, 'Killed', 5, 'Blocked', 6, 'ExtensionNotFound',
7, 'Inactive', 8, 'Disabled', 9, 'JobInitializationError'
]
;
JobHistory
| where PreciseTimeStamp > ago(1h)
| where Service != "AX"
| where Plugin has "Analytics"
| sort by PreciseTimeStamp desc
| join kind=leftouter TeamFoundationJobResult on Result
| extend ExecutionTimeSpan = totimespan(ExecutionTime)
| project JobName, StartTime, ExecutionTimeSpan, ResultString, ResultMessage
Kimlik başına en son kayıtları (zaman damgasına göre) alma
Aşağıdakileri içeren bir tablonuz olduğunu varsayalım:
- Kullanıcı
ID
kimliği veya düğüm kimliği gibi her satırın ilişkilendirildiği varlığı tanımlayan sütun timestamp
Satır için zaman başvurusu sağlayan sütun- Diğer sütunlar
Sütunun her değeri ID
için en son iki kaydı döndüren bir sorgu oluşturmak için en üstteki iç içe işlecini kullanabilirsiniz; burada en son değeri en yüksek değerine timestamp
sahip olarak tanımlanır:
datatable(id:string, timestamp:datetime, bla:string) // #1
[
"Barak", datetime(2015-01-01), "1",
"Barak", datetime(2016-01-01), "2",
"Barak", datetime(2017-01-20), "3",
"Donald", datetime(2017-01-20), "4",
"Donald", datetime(2017-01-18), "5",
"Donald", datetime(2017-01-19), "6"
]
| top-nested of id by dummy0=max(1), // #2
top-nested 2 of timestamp by dummy1=max(timestamp), // #3
top-nested of bla by dummy2=max(1) // #4
| project-away dummy0, dummy1, dummy2 // #5
Yukarıdaki sorgunun adım adım açıklaması aşağıdadır (numaralandırma, kod açıklamalarındaki sayılara karşılık gelir):
- ,
datatable
tanıtım amacıyla bazı test verileri oluşturmanın bir yoludur. Normalde burada gerçek verileri kullanırsınız. - Bu satır temelde değerinin
id
tüm benzersiz değerlerini döndüreceği anlamına gelir. - Bu satır daha sonra ekranı kaplayan ilk iki kayıt için şunu döndürür:
- Sütun
timestamp
- Önceki düzeyin sütunları (burada, yalnızca
id
) - Bu düzeyde belirtilen sütun (burada,
timestamp
)
- Sütun
- Bu satır, önceki düzey tarafından döndürülen kayıtların her biri için sütunun değerlerini
bla
ekler. Tabloda ilgilendiğiniz başka sütunlar varsa, bu sütunların her biri için bu satırı yineleyebilirsiniz. - Son satır, tarafından
top-nested
tanıtılan "ek" sütunları kaldırmak için proje dışarıda işlecini kullanır.
Tabloyu toplam hesaplamanın yüzdesine göre genişletme
Sayısal sütun içeren bir tablosal ifade, toplam yüzdesi olarak değeriyle birlikte geldiğinde kullanıcı için daha kullanışlıdır.
Örneğin, bir sorgunun aşağıdaki tabloyu ürettiğini varsayalım:
SomeSeries | SomeInt |
---|---|
Apple | 100 |
Muz | 200 |
Tabloyu aşağıdaki gibi göstermek istiyorsunuz:
SomeSeries | SomeInt | Pct |
---|---|---|
Apple | 100 | 33.3 |
Muz | 200 | 66.6 |
Tablonun görüntülenme biçimini değiştirmek için, sütunun toplamını SomeInt
(toplamı) hesaplayın ve bu sütunun her değerini toplama bölün. Rastgele sonuçlar için as işlecini kullanın.
Örneğin:
// The following table literally represents a long calculation
// that ends up with an anonymous tabular value:
datatable (SomeInt:int, SomeSeries:string) [
100, "Apple",
200, "Banana",
]
// We now give this calculation a name ("X"):
| as X
// Having this name we can refer to it in the sub-expression
// "X | summarize sum(SomeInt)":
| extend Pct = 100 * bin(todouble(SomeInt) / toscalar(X | summarize sum(SomeInt)), 0.001)
Kayan pencere üzerinde toplamalar gerçekleştirme
Aşağıdaki örnekte kayan pencere kullanarak sütunların nasıl özetlediği gösterilmektedir. Sorgu için, zaman damgalarına göre meyve fiyatlarını içeren aşağıdaki tabloyu kullanın.
Yedi günlük kayan bir pencere kullanarak her meyvenin günlük en düşük, en yüksek ve toplam maliyetlerini hesaplayın. Sonuç kümesindeki her kayıt önceki yedi günü toplar ve sonuçlar analiz döneminde günlük bir kayıt içerir.
Meyve tablosu:
Zaman damgası | Meyve | Fiyat |
---|---|---|
2018-09-24 21:00:00.0000000 | Muz | 3 |
2018-09-25 20:00:00.0000000 | Elma | 9 |
2018-09-26 03:00:00.0000000 | Muz | 4 |
2018-09-27 10:00:00.0000000 | Erik | 8 |
2018-09-28 07:00:00.0000000 | Muz | 6 |
2018-09-29 21:00:00.0000000 | Muz | 8 |
2018-09-30 01:00:00.0000000 | Erik | 2 |
2018-10-01 05:00:00.0000000 | Muz | 0 |
2018-10-02 02:00:00.0000000 | Muz | 0 |
2018-10-03 13:00:00.0000000 | Erik | 4 |
2018-10-04 14:00:00.0000000 | Elma | 8 |
2018-10-05 05:00:00.0000000 | Muz | 2 |
2018-10-06 08:00:00.0000000 | Erik | 8 |
2018-10-07 12:00:00.0000000 | Muz | 0 |
Kayan pencere toplama sorgusu aşağıdadır. Sorgu sonucundan sonraki açıklamaya bakın.
let _start = datetime(2018-09-24);
let _end = _start + 13d;
Fruits
| extend _bin = bin_at(Timestamp, 1d, _start) // #1
| extend _endRange = iff(_bin + 7d > _end, _end,
iff( _bin + 7d - 1d < _start, _start,
iff( _bin + 7d - 1d < _bin, _bin, _bin + 7d - 1d))) // #2
| extend _range = range(_bin, _endRange, 1d) // #3
| mv-expand _range to typeof(datetime) take 1000000 // #4
| summarize min(Price), max(Price), sum(Price) by Timestamp=bin_at(_range, 1d, _start) , Fruit // #5
| where Timestamp >= _start + 7d; // #6
Çıktı aşağıda verilmiştir:
Zaman damgası | Meyve | min_Price | max_Price | sum_Price |
---|---|---|---|---|
2018-10-01 00:00:00.0000000 | Elma | 9 | 9 | 9 |
2018-10-01 00:00:00.0000000 | Muz | 0 | 8 | 18 |
2018-10-01 00:00:00.0000000 | Erik | 2 | 8 | 10 |
2018-10-02 00:00:00.0000000 | Muz | 0 | 8 | 18 |
2018-10-02 00:00:00.0000000 | Erik | 2 | 8 | 10 |
2018-10-03 00:00:00.0000000 | Erik | 2 | 8 | 14 |
2018-10-03 00:00:00.0000000 | Muz | 0 | 8 | 14 |
2018-10-04 00:00:00.0000000 | Muz | 0 | 8 | 14 |
2018-10-04 00:00:00.0000000 | Erik | 2 | 4 | 6 |
2018-10-04 00:00:00.0000000 | Elma | 8 | 8 | 8 |
2018-10-05 00:00:00.0000000 | Muz | 0 | 8 | 10 |
2018-10-05 00:00:00.0000000 | Erik | 2 | 4 | 6 |
2018-10-05 00:00:00.0000000 | Elma | 8 | 8 | 8 |
2018-10-06 00:00:00.0000000 | Erik | 2 | 8 | 14 |
2018-10-06 00:00:00.0000000 | Muz | 0 | 2 | 2 |
2018-10-06 00:00:00.0000000 | Elma | 8 | 8 | 8 |
2018-10-07 00:00:00.0000000 | Muz | 0 | 2 | 2 |
2018-10-07 00:00:00.0000000 | Erik | 4 | 8 | 12 |
2018-10-07 00:00:00.0000000 | Elma | 8 | 8 | 8 |
Sorgu, giriş tablosundaki her kaydı gerçek görünümünden sonraki yedi gün boyunca "uzatır" (yineler). Her kayıt aslında yedi kez görünür. Sonuç olarak, günlük toplama önceki yedi günün tüm kayıtlarını içerir.
Önceki sorgunun adım adım açıklaması aşağıdadır:
- Her kaydı bir güne bölme (ile göreli olarak
_start
). - Kayıt başına aralığın sonunu belirleyin:
_bin + 7d
, değer ve_end
aralığının_start
dışında değilse, bu durumda ayarlanır. - Her kayıt için, geçerli kaydın gününden başlayarak yedi günlük (zaman damgaları) bir dizi oluşturun.
mv-expand
dizisini kullanarak her kaydı birbirinden bir gün ayrı olarak yedi kayda çoğaltabilir.- Her gün için toplama işlevini gerçekleştirin. #4 nedeniyle, bu adım aslında son yedi günü özetler.
- İlk yedi güne ait veriler eksiktir çünkü ilk yedi gün için yedi günlük bir geri arama süresi yoktur. İlk yedi gün nihai sonucun dışında tutulur. Örnekte, yalnızca 2018-10-01 için toplamaya katılırlar.
Önceki olayı bulma
Sonraki örnek, iki veri kümesi arasında önceki bir olayın nasıl bulunduğunu gösterir.
A ve B olmak üzere iki veri kümeniz vardır. B veri kümesindeki her kayıt için, A veri kümesinde önceki olayını (yani arg_max
A'daki hala B'den eski olan kaydı) bulun.
Örnek veri kümeleri şunlardır:
let A = datatable(Timestamp:datetime, ID:string, EventA:string)
[
datetime(2019-01-01 00:00:00), "x", "Ax1",
datetime(2019-01-01 00:00:01), "x", "Ax2",
datetime(2019-01-01 00:00:02), "y", "Ay1",
datetime(2019-01-01 00:00:05), "y", "Ay2",
datetime(2019-01-01 00:00:00), "z", "Az1"
];
let B = datatable(Timestamp:datetime, ID:string, EventB:string)
[
datetime(2019-01-01 00:00:03), "x", "B",
datetime(2019-01-01 00:00:04), "x", "B",
datetime(2019-01-01 00:00:04), "y", "B",
datetime(2019-01-01 00:02:00), "z", "B"
];
A; B
Çıkış
Zaman damgası | ID | OlayB |
---|---|---|
2019-01-01 00:00:00.0000000 | x | Ax1 |
2019-01-01 00:00:00.0000000 | z | Az1 |
2019-01-01 00:00:01.0000000 | x | Ax2 |
2019-01-01 00:00:02.0000000 | y | Ay1 |
2019-01-01 00:00:05.0000000 | y | Ay2 |
Zaman damgası | ID | EventA |
---|---|---|
2019-01-01 00:00:03.0000000 | x | B |
2019-01-01 00:00:04.0000000 | x | B |
2019-01-01 00:00:04.0000000 | y | B |
2019-01-01 00:02:00.0000000 | z | B |
Beklenen çıktı:
ID | Zaman damgası | OlayB | A_Timestamp | EventA |
---|---|---|---|---|
x | 2019-01-01 00:00:03.0000000 | B | 2019-01-01 00:00:01.0000000 | Ax2 |
x | 2019-01-01 00:00:04.0000000 | B | 2019-01-01 00:00:01.0000000 | Ax2 |
y | 2019-01-01 00:00:04.0000000 | B | 2019-01-01 00:00:02.0000000 | Ay1 |
z | 2019-01-01 00:02:00.0000000 | B | 2019-01-01 00:00:00.0000000 | Az1 |
Bu sorun için iki farklı yaklaşım önerilir. Senaryonuza en uygun olanı bulmak için her ikisini de kendi veri kümenizde test edebilirsiniz.
Not
Her yaklaşım farklı veri kümelerinde farklı çalıştırılabilir.
Yaklaşım 1
Bu yaklaşım hem veri kümelerini kimliğe hem de zaman damgasına göre seri hale getirmektedir. Ardından, B veri kümesindeki tüm olayları A veri kümesindeki önceki tüm olaylarıyla gruplandırıyor. Son olarak, gruptaki arg_max
A veri kümesindeki tüm olayları seçer.
A
| extend A_Timestamp = Timestamp, Kind="A"
| union (B | extend B_Timestamp = Timestamp, Kind="B")
| order by ID, Timestamp asc
| extend t = iff(Kind == "A" and (prev(Kind) != "A" or prev(Id) != ID), 1, 0)
| extend t = row_cumsum(t)
| summarize Timestamp=make_list(Timestamp), EventB=make_list(EventB), arg_max(A_Timestamp, EventA) by t, ID
| mv-expand Timestamp to typeof(datetime), EventB to typeof(string)
| where isnotempty(EventB)
| project-away t
Yaklaşım 2
Sorunu çözmek için bu yaklaşım için maksimum geri arama süresi gerekir. Yaklaşım, A veri kümesindeki kaydın B veri kümesiyle ne kadar eski olabileceğini gösterir. Yöntemi daha sonra kimlik ve bu geri arama dönemine göre iki veri kümesini birleştirir.
tüm join
olası adayları ve B veri kümesindeki kayıtlardan daha eski olan ve geri arama dönemi içinde bulunan tüm veri kümesi A kayıtlarını üretir. Ardından, B veri kümesine en yakın olan tarafından filtrelenmiş arg_min (TimestampB - TimestampA)
olur. Geri arama süresi ne kadar kısa olursa, sorgu sonuçları o kadar iyi olur.
Aşağıdaki örnekte, geri arama dönemi olarak 1m
ayarlanmıştır. Kimliği z
olan kaydın olayı iki dakika daha eski olduğundan A
buna karşılık gelen A
bir olay yoktur.
let _maxLookbackPeriod = 1m;
let _internalWindowBin = _maxLookbackPeriod / 2;
let B_events = B
| extend ID = new_guid()
| extend _time = bin(Timestamp, _internalWindowBin)
| extend _range = range(_time - _internalWindowBin, _time + _maxLookbackPeriod, _internalWindowBin)
| mv-expand _range to typeof(datetime)
| extend B_Timestamp = Timestamp, _range;
let A_events = A
| extend _time = bin(Timestamp, _internalWindowBin)
| extend _range = range(_time - _internalWindowBin, _time + _maxLookbackPeriod, _internalWindowBin)
| mv-expand _range to typeof(datetime)
| extend A_Timestamp = Timestamp, _range;
B_events
| join kind=leftouter (
A_events
) on ID, _range
| where isnull(A_Timestamp) or (A_Timestamp <= B_Timestamp and B_Timestamp <= A_Timestamp + _maxLookbackPeriod)
| extend diff = coalesce(B_Timestamp - A_Timestamp, _maxLookbackPeriod*2)
| summarize arg_min(diff, *) by ID
| project ID, B_Timestamp, A_Timestamp, EventB, EventA
Çıktı
ID | B_Timestamp | A_Timestamp | OlayB | EventA |
---|---|---|---|---|
x | 2019-01-01 00:00:03.0000000 | 2019-01-01 00:00:01.0000000 | B | Ax2 |
x | 2019-01-01 00:00:04.0000000 | 2019-01-01 00:00:01.0000000 | B | Ax2 |
y | 2019-01-01 00:00:04.0000000 | 2019-01-01 00:00:02.0000000 | B | Ay1 |
z | 2019-01-01 00:02:00.0000000 | B |
Sonraki adımlar
Bu makalede Azure İzleyici'deki yaygın sorgu gereksinimleri ve bunları karşılamak için Kusto Sorgu Dili nasıl kullanabileceğiniz tanımlanmaktadır.
Dize işlemleri
Aşağıdaki bölümlerde, Kusto Sorgu Dili kullanırken dizelerle çalışma örnekleri verilmiştir.
Dizeler ve kaçış yöntemleri
Dize değerleri tek veya çift tırnak içine alınır. Karakterin soluna ters eğik çizgi (\) ekleyerek karakterden kaçabilirsiniz: \t
sekme, yeni satır, \n
\'
tek tırnak karakteri ve \"
çift tırnak karakteri.
print "this is a 'string' literal in double \" quotes"
print 'this is a "string" literal in single \' quotes'
"\" öğesinin kaçış karakteri olarak davranmasını önlemek için dizeye ön ek olarak "@" ekleyin:
print @"C:\backslash\not\escaped\with @ prefix"
Dize karşılaştırmaları
İşleç | Açıklama | Duyarlı | Örnek (ödemeler true ) |
---|---|---|---|
== |
Eşittir | Yes | "aBc" == "aBc" |
!= |
Eşit değil | Yes | "abc" != "ABC" |
=~ |
Eşittir | No | "abc" =~ "ABC" |
!~ |
Eşit değil | No | "aBc" !~ "xyz" |
has |
Sağ taraftaki değer, sol taraftaki değerdeki terimin tamamıdır | No | "North America" has "america" |
!has |
Sağ taraftaki değer, sol taraftaki değerde tam bir terim değildir | No | "North America" !has "amer" |
has_cs |
Sağ taraftaki değer, sol taraftaki değerdeki terimin tamamıdır | Yes | "North America" has_cs "America" |
!has_cs |
Sağ taraftaki değer, sol taraftaki değerde tam bir terim değildir | Yes | "North America" !has_cs "amer" |
hasprefix |
Sağ taraftaki değer, sol taraftaki değerde bir terim ön ekidir | No | "North America" hasprefix "ame" |
!hasprefix |
Sağ taraftaki değer, sol taraftaki değerde terim ön eki değildir | No | "North America" !hasprefix "mer" |
hasprefix_cs |
Sağ taraftaki değer, sol taraftaki değerde bir terim ön ekidir | Yes | "North America" hasprefix_cs "Ame" |
!hasprefix_cs |
Sağ taraftaki değer, sol taraftaki değerde terim ön eki değildir | Yes | "North America" !hasprefix_cs "CA" |
hassuffix |
Sağ taraftaki değer, sol taraftaki değerde bir terim sonekidir | No | "North America" hassuffix "ica" |
!hassuffix |
Sağ taraftaki değer, sol taraftaki değerde terim soneki değildir | No | "North America" !hassuffix "americ" |
hassuffix_cs |
Sağ taraftaki değer, sol taraftaki değerde bir terim sonekidir | Yes | "North America" hassuffix_cs "ica" |
!hassuffix_cs |
Sağ taraftaki değer, sol taraftaki değerde terim soneki değildir | Yes | "North America" !hassuffix_cs "icA" |
contains |
Sağ taraftaki değer, sol taraftaki değerin alt dizileri olarak gerçekleşir | No | "FabriKam" contains "BRik" |
!contains |
Sağ taraftaki değer sol taraftaki değerde oluşmaz | No | "Fabrikam" !contains "xyz" |
contains_cs |
Sağ taraftaki değer, sol taraftaki değerin alt dizileri olarak gerçekleşir | Yes | "FabriKam" contains_cs "Kam" |
!contains_cs |
Sağ taraftaki değer sol taraftaki değerde oluşmaz | Yes | "Fabrikam" !contains_cs "Kam" |
startswith |
Sağ taraftaki değer, sol taraftaki değerin ilk alt dizisini oluşturur | No | "Fabrikam" startswith "fab" |
!startswith |
Sağ taraftaki değer, sol taraftaki değerin ilk alt dizilerinden biri değildir | No | "Fabrikam" !startswith "kam" |
startswith_cs |
Sağ taraftaki değer, sol taraftaki değerin ilk alt dizisini oluşturur | Yes | "Fabrikam" startswith_cs "Fab" |
!startswith_cs |
Sağ taraftaki değer, sol taraftaki değerin ilk alt dizilerinden biri değildir | Yes | "Fabrikam" !startswith_cs "fab" |
endswith |
Sağ taraftaki değer, sol taraftaki değerin kapanış alt dizidir | No | "Fabrikam" endswith "Kam" |
!endswith |
Sağ taraftaki değer, sol taraftaki değerin kapanış alt dizileri değildir | No | "Fabrikam" !endswith "brik" |
endswith_cs |
Sağ taraftaki değer, sol taraftaki değerin kapanış alt dizidir | Yes | "Fabrikam" endswith "Kam" |
!endswith_cs |
Sağ taraftaki değer, sol taraftaki değerin kapanış alt dizileri değildir | Yes | "Fabrikam" !endswith "brik" |
matches regex |
Sol taraftaki değer, sağ taraftaki değer için bir eşleşme içeriyor | Yes | "Fabrikam" matches regex "b.*k" |
in |
Öğelerden birine eşittir | Yes | "abc" in ("123", "345", "abc") |
!in |
Öğelerden hiçbirine eşit değildir | Yes | "bca" !in ("123", "345", "abc") |
countof
Bir alt dizenin dize içindeki oluşumlarını sayar. Düz dizeleri eşleştirebilir veya normal ifade (regex) kullanabilir. Düz dize eşleşmeleri çakışabilir, ancak regex eşleşmeleri çakışmaz.
countof(text, search [, kind])
text
: Giriş dizesisearch
: Metnin içinde eşleşmek için düz dize veya regexkind
: normal | regex (varsayılan: normal).
Arama dizesinin kapsayıcıda kaç kez eşleştirilebileceğini döndürür. Düz dize eşleşmeleri çakışabilir, ancak regex eşleşmeleri çakışmaz.
Düz dize eşleşmeleri
print countof("The cat sat on the mat", "at"); //result: 3
print countof("aaa", "a"); //result: 3
print countof("aaaa", "aa"); //result: 3 (not 2!)
print countof("ababa", "ab", "normal"); //result: 2
print countof("ababa", "aba"); //result: 2
Regex eşleşmeleri
print countof("The cat sat on the mat", @"\b.at\b", "regex"); //result: 3
print countof("ababa", "aba", "regex"); //result: 1
print countof("abcabc", "a.c", "regex"); // result: 2
Ayıklamak
Belirli bir dizeden normal ifade için eşleşme alır. İsteğe bağlı olarak, ayıklanan alt dizeyi belirtilen türe dönüştürebilir.
extract(regex, captureGroup, text [, typeLiteral])
regex
: Normal bir ifade.captureGroup
: Ayıklanması gereken yakalama grubunu gösteren pozitif bir tamsayı sabiti. Eşleşmenin tamamı için 0, normal ifadedeki ilk parantez () ile eşleşen değer için 1 ve sonraki parantezler için 2 veya daha fazla kullanın.text
- Aranacak dize.typeLiteral
- İsteğe bağlı bir tür değişmez değeri (örneğin,typeof(long)
). Sağlanırsa, ayıklanan alt dize bu türe dönüştürülür.
belirtilen yakalama grubuyla captureGroup
eşleşen alt dizeyi, isteğe bağlı olarak öğesine dönüştürülür typeLiteral
. Eşleşme yoksa veya tür dönüştürmesi başarısız olursa null döndürür.
Aşağıdaki örnek, sinyal kaydından son sekizlisini ComputerIP
ayıklar:
Heartbeat
| where ComputerIP != ""
| take 1
| project ComputerIP, last_octet=extract("([0-9]*$)", 1, ComputerIP)
Aşağıdaki örnek son sekizliyi ayıklar, gerçek bir türe (sayı) dönüştürür ve sonraki IP değerini hesaplar:
Heartbeat
| where ComputerIP != ""
| take 1
| extend last_octet=extract("([0-9]*$)", 1, ComputerIP, typeof(real))
| extend next_ip=(last_octet+1)%255
| project ComputerIP, last_octet, next_ip
Sonraki örnekte dizenin Trace
tanımı Duration
arandı. Eşleşme türüne real
atılır ve bir zaman sabiti (1 sn) ile çarpılır ve ardından türüne timespan
yayınlanırDuration
.
let Trace="A=12, B=34, Duration=567, ...";
print Duration = extract("Duration=([0-9.]+)", 1, Trace, typeof(real)); //result: 567
print Duration_seconds = extract("Duration=([0-9.]+)", 1, Trace, typeof(real)) * time(1s); //result: 00:09:27
isempty, isnotempty
isempty
bağımsız değişken boş dize veya null ise döndürürtrue
(bkzisnull
. ).isnotempty
bağımsız değişken boş dize veya null değilse döndürürtrue
(bkzisnotnull
. ). Diğer ad:isnotempty
.
isempty(value)
isnotempty(value)
Örnek
print isempty(""); // result: true
print isempty("0"); // result: false
print isempty(0); // result: false
print isempty(5); // result: false
Heartbeat | where isnotempty(ComputerIP) | take 1 // return 1 Heartbeat record in which ComputerIP isn't empty
parse_url
Url'yi protokol, konak ve bağlantı noktası gibi bölümlerine böler ve sonra dize olarak bölümleri içeren bir sözlük nesnesi döndürür.
parse_url(urlstring)
Örnek
print parse_url("http://user:pass@contoso.com/icecream/buy.aspx?a=1&b=2#tag")
Çıktı aşağıda verilmiştir:
{
"Scheme" : "http",
"Host" : "contoso.com",
"Port" : "80",
"Path" : "/icecream/buy.aspx",
"Username" : "user",
"Password" : "pass",
"Query Parameters" : {"a":"1","b":"2"},
"Fragment" : "tag"
}
replace_regex
Tüm regex eşleşmelerini başka bir dizeyle değiştirir.
replace_regex(regex, rewrite, input_text)
regex
: Eşleştirecek normal ifade. Parantez () içinde yakalama grupları içerebilir.rewrite
: Bir regex ile eşleştirilerek yapılan tüm eşleşmelerin yerine geçen regex. Tüm eşleşmeye başvurmak için \0, ilk yakalama grubu için \1, sonraki yakalama grupları için \2 vb. kullanın.input_text
: Aranacak giriş dizesi.
Regex'in tüm eşleşmelerini yeniden yazma değerlendirmeleriyle değiştirdikten sonra metni döndürür. Eşleşmeler çakışmaz.
Örnek
SecurityEvent
| take 1
| project Activity
| extend replaced = replace_regex(@"(\d+) -", @"Activity ID \1: ", Activity)
Çıktı aşağıda verilmiştir:
Etkinlik | Değiştirilir |
---|---|
4663 - Nesneye erişme girişiminde bulunuldu | Etkinlik Kimliği 4663: Bir nesneye erişme girişiminde bulunuldu. |
Split
Belirli bir dizeyi belirtilen sınırlayıcıya göre böler ve ardından sonuçta elde edilen alt dizelerin bir dizisini döndürür.
split(source, delimiter [, requestedIndex])
source
: Belirtilen sınırlayıcıya göre bölünecek dize.delimiter
: Kaynak dizeyi bölmek için kullanılacak sınırlayıcı.requestedIndex
: İsteğe bağlı sıfır tabanlı dizin. Sağlanırsa, döndürülen dize dizisi yalnızca bu öğeyi (varsa) tutar.
Örnek
print split("aaa_bbb_ccc", "_"); // result: ["aaa","bbb","ccc"]
print split("aa_bb", "_"); // result: ["aa","bb"]
print split("aaa_bbb_ccc", "_", 1); // result: ["bbb"]
print split("", "_"); // result: [""]
print split("a__b", "_"); // result: ["a","","b"]
print split("aabbcc", "bb"); // result: ["aa","cc"]
strcat
Dize bağımsız değişkenlerini birleştirir (1-16 bağımsız değişkenlerini destekler).
strcat("string1", "string2", "string3")
Örnek
print strcat("hello", " ", "world") // result: "hello world"
Strlen
Bir dizenin uzunluğunu döndürür.
strlen("text_to_evaluate")
Örnek
print strlen("hello") // result: 5
Dize
Belirtilen dizinden başlayarak belirli bir kaynak dizeden bir alt dize ayıklar. İsteğe bağlı olarak, istenen alt dizenin uzunluğunu belirtebilirsiniz.
substring(source, startingIndex [, length])
source
: Alt dizenin alındığı kaynak dize.startingIndex
: İstenen alt dizenin sıfır tabanlı başlangıç karakteri konumu.length
: Döndürülen alt dizenin istenen uzunluğunu belirtmek için kullanabileceğiniz isteğe bağlı bir parametre.
Örnek
print substring("abcdefg", 1, 2); // result: "bc"
print substring("123456", 1); // result: "23456"
print substring("123456", 2, 2); // result: "34"
print substring("ABCD", 0, 2); // result: "AB"
tolower,upper
Belirli bir dizeyi tümü küçük harfe veya tümü büyük harfe dönüştürür.
tolower("value")
toupper("value")
Örnek
print tolower("HELLO"); // result: "hello"
print toupper("hello"); // result: "HELLO"
Tarih ve saat işlemleri
Aşağıdaki bölümlerde, Kusto Sorgu Dili kullanırken tarih ve saat değerleriyle çalışma örnekleri verilmiştir.
Tarih-saat temel bilgileri
Kusto Sorgu Dili tarih ve saatlerle ilişkili iki ana veri türü vardır: datetime
ve timespan
. Tüm tarihler UTC olarak ifade edilir. Birden çok tarih-saat biçimi desteklense de ISO-8601 biçimi tercih edilir.
Zaman aralığı ondalık olarak ve ardından bir zaman birimi olarak ifade edilir:
Steno | Zaman birimi |
---|---|
d | gün |
h | saat |
m | dakika |
s | saniye |
Bayan | milisaniye |
Microsecond | Microsecond |
Kene | Içerir |
işlecini kullanarak todatetime
bir dize yayınlayarak tarih-saat değerleri oluşturabilirsiniz. Örneğin, belirli bir zaman aralığında gönderilen VM sinyallerini gözden geçirmek için işlecini between
kullanarak bir zaman aralığı belirtin:
Heartbeat
| where TimeGenerated between(datetime("2018-06-30 22:46:42") .. datetime("2018-07-01 00:57:27"))
Bir diğer yaygın senaryo da tarih-saat değerini günümüzle karşılaştırmaktır. Örneğin, son iki dakikadaki tüm sinyalleri görmek için işlecini iki dakikayı now
temsil eden bir zaman aralığıyla birlikte kullanabilirsiniz:
Heartbeat
| where TimeGenerated > now() - 2m
Bu işlev için bir kısayol da kullanılabilir:
Heartbeat
| where TimeGenerated > now(-2m)
En kısa ve en okunabilir yöntem işlecini ago
kullanmaktır:
Heartbeat
| where TimeGenerated > ago(2m)
Başlangıç ve bitiş saatlerini bilmek yerine başlangıç saatini ve süresini bildiğinizi varsayalım. Sorguyu yeniden yazabilirsiniz:
let startDatetime = todatetime("2018-06-30 20:12:42.9");
let duration = totimespan(25m);
Heartbeat
| where TimeGenerated between(startDatetime .. (startDatetime+duration) )
| extend timeFromStart = TimeGenerated - startDatetime
Zaman birimlerini dönüştürme
Tarih-saat veya zaman aralığı değerini varsayılan değer dışında bir zaman biriminde ifade etmek isteyebilirsiniz. Örneğin, son 30 dakikadaki hata olaylarını gözden geçiriyorsanız ve olayın ne kadar önce gerçekleştiğini gösteren bir hesaplanmış sütuna ihtiyacınız varsa şu sorguyu kullanabilirsiniz:
Event
| where TimeGenerated > ago(30m)
| where EventLevelName == "Error"
| extend timeAgo = now() - TimeGenerated
Sütun, timeAgo
gibi hh:mm:ss.fffffff olarak biçimlendirilmiş değerleri 00:09:31.5118992
tutar. Bu değerleri başlangıç zamanından bu yana dakika number
cinsinden biçimlendirmek istiyorsanız, bu değeri 1m
değerine bölün:
Event
| where TimeGenerated > ago(30m)
| where EventLevelName == "Error"
| extend timeAgo = now() - TimeGenerated
| extend timeAgoMinutes = timeAgo/1m
Zaman aralıklarına göre toplamalar ve demetlemeler
Bir diğer yaygın senaryo ise belirli bir zaman birimindeki belirli bir zaman aralığına ait istatistikleri elde etme gereksinimidir. Bu senaryo için bir işleci yan bin
tümcesinin summarize
parçası olarak kullanabilirsiniz.
Son yarım saat içinde beş dakikada bir gerçekleşen olayların sayısını almak için aşağıdaki sorguyu kullanın:
Event
| where TimeGenerated > ago(30m)
| summarize events_count=count() by bin(TimeGenerated, 5m)
Bu sorgu aşağıdaki tabloyu oluşturur:
TimeGenerated(UTC) | events_count |
---|---|
2018-08-01T09:30:00 | 54 |
2018-08-01T09:35:00 | 41 |
2018-08-01T09:40:00 | 42 |
2018-08-01T09:45:00 | 41 |
2018-08-01T09:50:00 | 41 |
2018-08-01T09:55:00 | 16 |
Sonuç demetleri oluşturmanın bir diğer yolu da gibi startofday
işlevleri kullanmaktır:
Event
| where TimeGenerated > ago(4d)
| summarize events_count=count() by startofday(TimeGenerated)
Çıktı aşağıda verilmiştir:
timestamp | Sayısı_ |
---|---|
2018-07-28T00:00:00 | 7,136 |
2018-07-29T00:00:00 | 12,315 |
2018-07-30T00:00:00 | 16,847 |
2018-07-31T00:00:00 | 12,616 |
2018-08-01T00:00:00 | 5,416 |
Saat dilimleri
Tüm tarih-saat değerleri UTC ile ifade edildiğinden, genellikle bu değerleri yerel saat dilimine dönüştürmek yararlı olur. Örneğin, UTC'yi PST saatlerine dönüştürmek için bu hesaplamayı kullanın:
Event
| extend localTimestamp = TimeGenerated - 8h
Toplamalar
Aşağıdaki bölümlerde, Kusto Sorgu Dili kullanırken bir sorgunun sonuçlarını toplamaya ilişkin örnekler verilmiştir.
count
Filtre uygulandıktan sonra sonuç kümesindeki satır sayısını sayma. Aşağıdaki örnek, tablodaki son 30 dakikadaki Perf
toplam satır sayısını döndürür. Sonuçlar, sütuna belirli bir ad atamadığınız sürece adlı count_
bir sütunda döndürülür:
Perf
| where TimeGenerated > ago(30m)
| summarize count()
Perf
| where TimeGenerated > ago(30m)
| summarize num_of_records=count()
Zaman çizelgesi görselleştirmeleri zaman içindeki eğilimi görmek için yararlı olabilir:
Perf
| where TimeGenerated > ago(30m)
| summarize count() by bin(TimeGenerated, 5m)
| render timechart
Bu örnekteki çıkış, beş dakikalık aralıklarla kayıt sayısı eğilim çizgisini gösterir Perf
:
dcount, dcountif
Belirli bir sütundaki ayrı değerleri saymak için ve dcountif
kullanındcount
. Aşağıdaki sorgu, son bir saat içinde kaç ayrı bilgisayarın sinyal gönderdiğini değerlendirir:
Heartbeat
| where TimeGenerated > ago(1h)
| summarize dcount(Computer)
Yalnızca sinyal gönderen Linux bilgisayarları saymak için kullanın dcountif
:
Heartbeat
| where TimeGenerated > ago(1h)
| summarize dcountif(Computer, OSType=="Linux")
Alt grupları değerlendirme
Verilerinizdeki alt gruplarda sayım veya diğer toplamaları gerçekleştirmek için anahtar sözcüğünü by
kullanın. Örneğin, her ülkede veya bölgede sinyal gönderen ayrı Linux bilgisayarlarının sayısını saymak için şu sorguyu kullanın:
Heartbeat
| where TimeGenerated > ago(1h)
| summarize distinct_computers=dcountif(Computer, OSType=="Linux") by RemoteIPCountry
Çıkış
RemoteIPCountry | distinct_computers |
---|---|
Birleşik Devletler | 19 |
Kanada | 3 |
İrlanda | 0 |
Birleşik Krallık | 0 |
Hollanda | 2 |
Verilerinizin daha küçük alt gruplarını analiz etmek için bölüme by
sütun adları ekleyin. Örneğin, işletim sistemi türü başına her bir ülke veya bölgeden ayrı bilgisayarları saymak isteyebilirsiniz (OSType
):
Heartbeat
| where TimeGenerated > ago(1h)
| summarize distinct_computers=dcountif(Computer, OSType=="Linux") by RemoteIPCountry, OSType
Yüzdebirlik
Ortanca değeri bulmak için işlevini bir değerle birlikte kullanarak percentile
yüzdebirlik değeri belirtin:
Perf
| where TimeGenerated > ago(30m)
| where CounterName == "% Processor Time" and InstanceName == "_Total"
| summarize percentiles(CounterValue, 50) by Computer
Ayrıca, her birine yönelik bir toplu sonuç almak için farklı yüzdebirlik dilimler de belirtebilirsiniz:
Perf
| where TimeGenerated > ago(30m)
| where CounterName == "% Processor Time" and InstanceName == "_Total"
| summarize percentiles(CounterValue, 25, 50, 75, 90) by Computer
Sonuçlar bazı bilgisayar CPU'larının benzer ortanca değerlere sahip olduğunu gösterebilir. Ancak, bazı bilgisayarlar ortanca değer etrafında sabit olsa da, diğerleri çok daha düşük ve daha yüksek CPU değerleri bildirdi. Yüksek ve düşük değerler, bilgisayarların ani artışlarla karşılaştığı anlamına gelir.
Varyans
Bir değerin varyansını doğrudan değerlendirmek için standart sapma ve varyans yöntemlerini kullanın:
Perf
| where TimeGenerated > ago(30m)
| where CounterName == "% Processor Time" and InstanceName == "_Total"
| summarize stdev(CounterValue), variance(CounterValue) by Computer
CPU kullanımının kararlılığını analiz etmenin iyi bir yolu, ortanca hesaplama ile birleştirmektir stdev
:
Perf
| where TimeGenerated > ago(130m)
| where CounterName == "% Processor Time" and InstanceName == "_Total"
| summarize stdev(CounterValue), percentiles(CounterValue, 50) by Computer
Listeler ve kümeler oluşturma
Verileri belirli bir sütundaki değerlerin sırasına göre özetlerken kullanabilirsiniz make_list
. Örneğin, bilgisayarlarınızda gerçekleşen en yaygın sıra olaylarını keşfetmek isteyebilirsiniz. Verileri temelde her bilgisayardaki değerlerin EventID
sırasına göre özetleyebilirsiniz:
Event
| where TimeGenerated > ago(12h)
| order by TimeGenerated desc
| summarize make_list(EventID) by Computer
Çıktı aşağıda verilmiştir:
Bilgisayar | list_EventID |
---|---|
bilgisayar1 | [704,701,1501,1500,1085,704,704,701] |
bilgisayar2 | [326,105,302,301,300,102] |
... | ... |
make_list
, verilerin bu listeye geçirildiği sırada bir liste oluşturur. Olayları en eskiden en yeniye sıralamak için yerine deyiminde order
desc
kullanınasc
.
Yalnızca farklı değerlerin listesini oluşturmak yararlı olabilir. Bu listeye küme adı verilir ve komutunu kullanarak make_set
oluşturabilirsiniz:
Event
| where TimeGenerated > ago(12h)
| order by TimeGenerated desc
| summarize make_set(EventID) by Computer
Çıktı aşağıda verilmiştir:
Bilgisayar | list_EventID |
---|---|
bilgisayar1 | [704,701,1501,1500,1085] |
bilgisayar2 | [326,105,302,301,300,102] |
... | ... |
gibi make_list
, make_set
sıralı verilerle de çalışır. komutu, make_set
içine geçirilen satırların sırasına göre diziler oluşturur.
Listeleri genişletme
veya öğesinin make_list
ters işlemidirmv-expand
.make_set
komut, mv-expand
değerlerin listesini genişleterek satırları ayırır. JSON ve dizi sütunları da dahil olmak üzere herhangi bir sayıda dinamik sütun arasında genişletilebilir. Örneğin, son bir saat içinde sinyal gönderen bilgisayarlardan veri gönderen çözümler için tabloya bakabilirsiniz Heartbeat
:
Heartbeat
| where TimeGenerated > ago(1h)
| project Computer, Solutions
Çıktı aşağıda verilmiştir:
Bilgisayar | Çözümler |
---|---|
bilgisayar1 | "security", "updates", "changeTracking" |
bilgisayar2 | "security", "updates" |
bilgisayar3 | "antiMalware", "changeTracking" |
... | ... |
Her değeri virgülle ayrılmış liste yerine ayrı bir satırda göstermek için kullanın mv-expand
:
Heartbeat
| where TimeGenerated > ago(1h)
| project Computer, split(Solutions, ",")
| mv-expand Solutions
Çıktı aşağıda verilmiştir:
Bilgisayar | Çözümler |
---|---|
bilgisayar1 | "güvenlik" |
bilgisayar1 | "güncelleştirmeler" |
bilgisayar1 | "changeTracking" |
bilgisayar2 | "güvenlik" |
bilgisayar2 | "güncelleştirmeler" |
bilgisayar3 | "kötü amaçlı yazılımdan koruma" |
bilgisayar3 | "changeTracking" |
... | ... |
Öğeleri birlikte gruplandırmak için kullanabilirsiniz make_list
. Çıktıda, çözüm başına bilgisayar listesini görebilirsiniz:
Öğeleri birlikte gruplandırmak için kullanabilirsiniz make_list
. Çıktıda, çözüm başına bilgisayar listesini görebilirsiniz:
Heartbeat
| where TimeGenerated > ago(1h)
| project Computer, split(Solutions, ",")
| mv-expand Solutions
| summarize make_list(Computer) by tostring(Solutions)
Çıktı aşağıda verilmiştir:
Çözümler | list_Computer |
---|---|
"güvenlik" | ["bilgisayar1", "bilgisayar2"] |
"güncelleştirmeler" | ["bilgisayar1", "bilgisayar2"] |
"changeTracking" | ["bilgisayar1", "bilgisayar3"] |
"kötü amaçlı yazılımdan koruma" | ["bilgisayar3"] |
... | ... |
Eksik bölmeler
uygulamasının mv-expand
kullanışlı bir uygulaması eksik bölmeler için varsayılan değerleri doldurmaktır. Örneğin, belirli bir bilgisayarın sinyalini keşfederek çalışma süresini aradığınızı varsayalım. Ayrıca, sütunundaki Category
sinyalin kaynağını da görmek istiyorsunuz. Normalde temel summarize
bir deyim kullanırız:
Heartbeat
| where TimeGenerated > ago(12h)
| summarize count() by Category, bin(TimeGenerated, 1h)
Çıktı aşağıda verilmiştir:
Kategori | TimeGenerated | Sayısı_ |
---|---|---|
Doğrudan Aracı | 2017-06-06T17:00:00Z | 15 |
Doğrudan Aracı | 2017-06-06T18:00:00Z | 60 |
Doğrudan Aracı | 2017-06-06T20:00:00Z | 55 |
Doğrudan Aracı | 2017-06-06T21:00:00Z | 57 |
Doğrudan Aracı | 2017-06-06T22:00:00Z | 60 |
... | ... | ... |
Çıkışta, "2017-06-06T19:00:00Z" ile ilişkili demet eksiktir çünkü bu saat için sinyal verisi yoktur. make-series
Boş demetlere varsayılan değer atamak için işlevini kullanın. Her kategori için bir satır oluşturulur. Çıkış, biri değerler ve diğeri de eşleşen zaman demetleri için iki ek dizi sütunu içerir:
Heartbeat
| make-series count() default=0 on TimeGenerated in range(ago(1d), now(), 1h) by Category
Çıktı aşağıda verilmiştir:
Category | Sayısı_ | TimeGenerated |
---|---|---|
Doğrudan Aracı | [15,60,0,55,60,57,60,...] | ["2017-06-06T17:00:00.0000000Z","2017-06-06T18:00:00.0000000Z","2017-06-06T19:00:00.0000000Z","2017-06-06T20:00:00.0000000Z","2017-06-06T21:00:00.0000000Z",...] |
... | ... | ... |
count_ dizisinin üçüncü öğesi beklendiği gibi 0'dır. TimeGenerated dizisinin eşleşen zaman damgası "2017-06-06T19:00:00.0000000Z" şeklindedir. Ancak, bu dizi biçimini okumak zordur. Dizileri genişletmek ve tarafından summarize
oluşturulanla aynı biçim çıkışını oluşturmak için kullanınmv-expand
:
Heartbeat
| make-series count() default=0 on TimeGenerated in range(ago(1d), now(), 1h) by Category
| mv-expand TimeGenerated, count_
| project Category, TimeGenerated, count_
Çıktı aşağıda verilmiştir:
Kategori | TimeGenerated | Sayısı_ |
---|---|---|
Doğrudan Aracı | 2017-06-06T17:00:00Z | 15 |
Doğrudan Aracı | 2017-06-06T18:00:00Z | 60 |
Doğrudan Aracı | 2017-06-06T19:00:00Z | 0 |
Doğrudan Aracı | 2017-06-06T20:00:00Z | 55 |
Doğrudan Aracı | 2017-06-06T21:00:00Z | 57 |
Doğrudan Aracı | 2017-06-06T22:00:00Z | 60 |
... | ... | ... |
Sonuçları bir öğe kümesine daraltın: let, make_set, toscalar, in
Yaygın bir senaryo, belirli varlıkların adlarını bir ölçüt kümesine göre seçmek ve ardından farklı bir veri kümesini bu varlık kümesine göre filtrelemektir. Örneğin, eksik güncelleştirmeleri olduğu bilinen bilgisayarları bulabilir ve bu bilgisayarların çağrıldığı IP adreslerini tanımlayabilirsiniz.
Aşağıda bir örnek verilmiştir:
let ComputersNeedingUpdate = toscalar(
Update
| summarize make_set(Computer)
| project set_Computer
);
WindowsFirewall
| where Computer in (ComputersNeedingUpdate)
Birleştirmeler
Birleştirmeleri kullanarak aynı sorgudaki birden çok tablodaki verileri analiz edebilirsiniz. Birleştirme, belirtilen sütunların değerlerini eşleştirerek iki veri kümesinin satırlarını birleştirir.
Aşağıda bir örnek verilmiştir:
SecurityEvent
| where EventID == 4624 // sign-in events
| project Computer, Account, TargetLogonId, LogonTime=TimeGenerated
| join kind= inner (
SecurityEvent
| where EventID == 4634 // sign-out events
| project TargetLogonId, LogoffTime=TimeGenerated
) on TargetLogonId
| extend Duration = LogoffTime-LogonTime
| project-away TargetLogonId1
| top 10 by Duration desc
Örnekte, ilk veri kümesi tüm oturum açma olayları için filtrelenir. Bu veri kümesi, tüm oturum kapatma olaylarını filtreleyen ikinci bir veri kümesiyle birleştirilir. Öngörülen sütunlar , Account
, TargetLogonId
ve TimeGenerated
sütunlarıdırComputer
. Veri kümeleri paylaşılan bir sütunla TargetLogonId
ilişkilendirilir. Çıkış, hem oturum açma hem de oturum kapatma süresine sahip bağıntı başına tek bir kayıttır.
Her iki veri kümesinde de aynı ada sahip sütunlar varsa, sağ taraftaki veri kümesinin sütunlarına dizin numarası verilir. Bu örnekte sonuçlar sol taraftaki tablodaki değerlerle ve TargetLogonId1
sağ taraftaki tablodaki değerlerle gösterilirTargetLogonId
. Bu durumda, ikinci TargetLogonId1
sütun işleci kullanılarak project-away
kaldırıldı.
Not
Performansı geliştirmek için işlecini kullanarak project
yalnızca birleştirilmiş veri kümelerinin ilgili sütunlarını tutun.
Birleştirilen anahtarın iki tablo arasında farklı bir ada sahip olduğu iki veri kümesini birleştirmek için aşağıdaki söz dizimini kullanın:
Table1
| join ( Table2 )
on $left.key1 == $right.key2
Arama tabloları
Birleştirmelerin yaygın kullanımlarından biri, statik değer eşlemesi için kullanmaktır datatable
. kullanmak datatable
, sonuçların daha ulaşılabilir olmasını sağlayabilir. Örneğin, güvenlik olayı verilerini her olay kimliği için olay adıyla zenginleştirebilirsiniz:
let DimTable = datatable(EventID:int, eventName:string)
[
4625, "Account activity",
4688, "Process action",
4634, "Account activity",
4658, "The handle to an object was closed",
4656, "A handle to an object was requested",
4690, "An attempt was made to duplicate a handle to an object",
4663, "An attempt was made to access an object",
5061, "Cryptographic operation",
5058, "Key file operation"
];
SecurityEvent
| join kind = inner
DimTable on EventID
| summarize count() by eventName
Çıktı aşağıda verilmiştir:
eventName | Sayısı_ |
---|---|
Nesnenin tanıtıcısı kapatıldı | 290,995 |
Bir nesnenin tanıtıcısı istendi | 154,157 |
Bir tanıtıcıyı nesneye çoğaltma girişiminde bulunuldu | 144,305 |
Bir nesneye erişme girişiminde bulunuldu | 123,669 |
Şifreleme işlemi | 153,495 |
Anahtar dosyası işlemi | 153,496 |
JSON ve veri yapıları
İç içe nesneler, dizideki veya anahtar-değer çiftlerinin eşlemindeki diğer nesneleri içeren nesnelerdir. Nesneler JSON dizeleri olarak temsil edilir. Bu bölümde verileri almak ve iç içe nesneleri analiz etmek için JSON'ı nasıl kullanabileceğiniz açıklanmaktadır.
JSON dizeleriyle çalışma
Bilinen bir yolda belirli bir JSON öğesine erişmek için veya extract_json()
kullanınextractjson
. Bu işlev, aşağıdaki kuralları kullanan bir yol ifadesi gerektirir:
- Kök klasöre başvurmak için kullanın $ .
- Aşağıdaki örneklerde gösterildiği gibi dizinlere ve öğelere başvurmak için köşeli ayraç veya nokta gösterimini kullanın.
Öğeleri ayırmak için dizinler ve noktalar için köşeli ayraç kullanın:
let hosts_report='{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"location":"South_DC", "status":"stopped", "rate":3}]}';
print hosts_report
| extend status = extract_json("$.hosts[0].status", hosts_report)
Bu örnek benzerdir ancak yalnızca köşeli ayraç gösterimini kullanır:
let hosts_report='{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"location":"South_DC", "status":"stopped", "rate":3}]}';
print hosts_report
| extend status = extract_json("$['hosts'][0]['status']", hosts_report)
Yalnızca bir öğe için yalnızca nokta gösterimini kullanabilirsiniz:
let hosts_report=dynamic({"location":"North_DC", "status":"running", "rate":5});
print hosts_report
| extend status = hosts_report.status
parsejson
JSON yapınızdaki birden çok öğeye dinamik nesne olarak erişmek en kolayıdır. Metin verilerini dinamik bir nesneye atamak için kullanın parsejson
. JSON'yi dinamik bir türe dönüştürdükten sonra, verileri çözümlemek için ek işlevler kullanabilirsiniz.
let hosts_object = parsejson('{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"location":"South_DC", "status":"stopped", "rate":3}]}');
print hosts_object
| extend status0=hosts_object.hosts[0].status, rate1=hosts_object.hosts[1].rate
array_length
Dizideki öğelerin sayısını saymak için kullanın array_length
:
let hosts_object = parsejson('{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"location":"South_DC", "status":"stopped", "rate":3}]}');
print hosts_object
| extend hosts_num=array_length(hosts_object.hosts)
mv-expand
Bir nesnenin özelliklerini ayrı satırlara bölmek için kullanın mv-expand
:
let hosts_object = parsejson('{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"location":"South_DC", "status":"stopped", "rate":3}]}');
print hosts_object
| mv-expand hosts_object.hosts[0]
buildschema
Bir nesnenin tüm değerlerini kabul eden şemayı almak için kullanın buildschema
:
let hosts_object = parsejson('{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"location":"South_DC", "status":"stopped", "rate":3}]}');
print hosts_object
| summarize buildschema(hosts_object)
Sonuç, JSON biçiminde bir şemadır:
{
"hosts":
{
"indexer":
{
"location": "string",
"rate": "int",
"status": "string"
}
}
}
Şema, nesne alanlarının adlarını ve eşleşen veri türlerini açıklar.
İç içe nesneler, aşağıdaki örnekte olduğu gibi farklı şemalara sahip olabilir:
let hosts_object = parsejson('{"hosts": [{"location":"North_DC", "status":"running", "rate":5},{"status":"stopped", "rate":"3", "range":100}]}');
print hosts_object
| summarize buildschema(hosts_object)
Grafikler
Aşağıdaki bölümlerde, Kusto Sorgu Dili kullanırken grafiklerle çalışma örnekleri verilmiştir.
Sonuçların grafiğini oluşturma
Son bir saat içinde işletim sistemi başına bilgisayar sayısını gözden geçirerek başlayın:
Heartbeat
| where TimeGenerated > ago(1h)
| summarize count(Computer) by OSType
Varsayılan olarak sonuçlar tablo olarak görüntülenir:
Daha kullanışlı bir görünüm için Grafik'i seçin ve ardından pasta seçeneğini belirleyerek sonuçları görselleştirin:
Zaman Çizelgeleri
bir saatlik bölmelerde işlemci süresinin ortalamasını ve 50. ve 95. yüzdebirlik dilimlerini gösterin.
Aşağıdaki sorgu birden çok seri oluşturur. Sonuçlarda, zaman çizelgesinde hangi serinin gösterileceğini seçebilirsiniz.
Perf
| where TimeGenerated > ago(1d)
| where CounterName == "% Processor Time"
| summarize avg(CounterValue), percentiles(CounterValue, 50, 95) by bin(TimeGenerated, 1h)
Çizgi grafik görüntüleme seçeneğini belirleyin:
Başvuru satırı
Başvuru satırı, ölçümün belirli bir eşiği aşıp aşmadığını kolayca belirlemenize yardımcı olabilir. Grafiğe çizgi eklemek için sabit sütun ekleyerek veri kümesini genişletin:
Perf
| where TimeGenerated > ago(1d)
| where CounterName == "% Processor Time"
| summarize avg(CounterValue), percentiles(CounterValue, 50, 95) by bin(TimeGenerated, 1h)
| extend Threshold = 20
Birden çok boyut
yan tümcesindeki by
summarize
birden çok ifade, sonuçlarda birden çok satır oluşturur. Her değer bileşimi için bir satır oluşturulur.
SecurityEvent
| where TimeGenerated > ago(1d)
| summarize count() by tostring(EventID), AccountType, bin(TimeGenerated, 1h)
Sonuçları grafik olarak görüntülediğinizde, grafik yan tümcesindeki by
ilk sütunu kullanır. Aşağıdaki örnekte, değeri kullanılarak oluşturulan yığılmış sütun grafiği gösterilmektedir EventID
. Boyutlar türünde string
olmalıdır. Bu örnekte EventID
, değeri olarak string
atılır:
Sütun adı için açılan oku seçerek sütunlar arasında geçiş yapabilirsiniz:
Akıllı analiz
Bu bölüm, kullanıcı etkinliğini analiz etmek için Azure Log Analytics'teki akıllı analiz işlevlerini kullanan örnekleri içerir. Azure Uygulaması Insights tarafından izlenen kendi uygulamalarınızı analiz etmek için bu örnekleri kullanabilir veya diğer verilerde benzer analizler için bu sorgulardaki kavramları kullanabilirsiniz.
Kohort analizi
Kohort analizi, kohort olarak bilinen belirli kullanıcı gruplarının etkinliğini izler. Kohort analizi, geri dönen kullanıcıların oranını ölçerek bir hizmetin ne kadar çekici olduğunu ölçmeye çalışır. Kullanıcılar, hizmeti ilk kullandıkları zamana göre gruplandırılır. Kohortları analiz ederken, ilk izlenen dönemlerde etkinlikte bir düşüş bulmayı bekliyoruz. Her kohort, üyelerinin ilk kez gözlemlendiği haftaya göre adlandırılır.
Aşağıdaki örnek, kullanıcıların hizmeti ilk kullanmalarından sonraki beş hafta içinde tamamladıkları etkinlik sayısını analiz eder:
let startDate = startofweek(bin(datetime(2017-01-20T00:00:00Z), 1d));
let week = range Cohort from startDate to datetime(2017-03-01T00:00:00Z) step 7d;
// For each user, we find the first and last timestamp of activity
let FirstAndLastUserActivity = (end:datetime)
{
customEvents
| where customDimensions["sourceapp"]=="ai-loganalyticsui-prod"
// Check 30 days back to see first time activity.
| where timestamp > startDate - 30d
| where timestamp < end
| summarize min=min(timestamp), max=max(timestamp) by user_AuthenticatedId
};
let DistinctUsers = (cohortPeriod:datetime, evaluatePeriod:datetime) {
toscalar (
FirstAndLastUserActivity(evaluatePeriod)
// Find members of the cohort: only users that were observed in this period for the first time.
| where min >= cohortPeriod and min < cohortPeriod + 7d
// Pick only the members that were active during the evaluated period or after.
| where max > evaluatePeriod - 7d
| summarize dcount(user_AuthenticatedId))
};
week
| where Cohort == startDate
// Finally, calculate the desired metric for each cohort. In this sample, we calculate distinct users but you can change
// this to any other metric that would measure the engagement of the cohort members.
| extend
r0 = DistinctUsers(startDate, startDate+7d),
r1 = DistinctUsers(startDate, startDate+14d),
r2 = DistinctUsers(startDate, startDate+21d),
r3 = DistinctUsers(startDate, startDate+28d),
r4 = DistinctUsers(startDate, startDate+35d)
| union (week | where Cohort == startDate + 7d
| extend
r0 = DistinctUsers(startDate+7d, startDate+14d),
r1 = DistinctUsers(startDate+7d, startDate+21d),
r2 = DistinctUsers(startDate+7d, startDate+28d),
r3 = DistinctUsers(startDate+7d, startDate+35d) )
| union (week | where Cohort == startDate + 14d
| extend
r0 = DistinctUsers(startDate+14d, startDate+21d),
r1 = DistinctUsers(startDate+14d, startDate+28d),
r2 = DistinctUsers(startDate+14d, startDate+35d) )
| union (week | where Cohort == startDate + 21d
| extend
r0 = DistinctUsers(startDate+21d, startDate+28d),
r1 = DistinctUsers(startDate+21d, startDate+35d) )
| union (week | where Cohort == startDate + 28d
| extend
r0 = DistinctUsers (startDate+28d, startDate+35d) )
// Calculate the retention percentage for each cohort by weeks
| project Cohort, r0, r1, r2, r3, r4,
p0 = r0/r0*100,
p1 = todouble(r1)/todouble (r0)*100,
p2 = todouble(r2)/todouble(r0)*100,
p3 = todouble(r3)/todouble(r0)*100,
p4 = todouble(r4)/todouble(r0)*100
| sort by Cohort asc
Çıktı aşağıda verilmiştir:
Aylık etkin kullanıcılar ve kullanıcı sürekliliği
Aşağıdaki örnek , series_fir işleviyle zaman serisi analizini kullanır. Kayan series_fir
pencere hesaplamaları için işlevini kullanabilirsiniz. İzlenen örnek uygulama, özel olaylar aracılığıyla kullanıcıların etkinliklerini izleyen bir çevrimiçi mağazadır. Sorgu iki tür kullanıcı etkinliğini izler: AddToCart
ve Checkout
. Etkin bir kullanıcıyı, belirli bir günde en az bir kez kullanıma alma işlemi tamamlayan bir kullanıcı olarak tanımlar.
let endtime = endofday(datetime(2017-03-01T00:00:00Z));
let window = 60d;
let starttime = endtime-window;
let interval = 1d;
let user_bins_to_analyze = 28;
// Create an array of filters coefficients for series_fir(). A list of '1' in our case will produce a simple sum.
let moving_sum_filter = toscalar(range x from 1 to user_bins_to_analyze step 1 | extend v=1 | summarize make_list(v));
// Level of engagement. Users will be counted as engaged if they completed at least this number of activities.
let min_activity = 1;
customEvents
| where timestamp > starttime
| where customDimensions["sourceapp"] == "ai-loganalyticsui-prod"
// We want to analyze users who actually checked out in our website.
| where (name == "Checkout") and user_AuthenticatedId <> ""
// Create a series of activities per user.
| make-series UserClicks=count() default=0 on timestamp
in range(starttime, endtime-1s, interval) by user_AuthenticatedId
// Create a new column that contains a sliding sum.
// Passing 'false' as the last parameter to series_fir() prevents normalization of the calculation by the size of the window.
// For each time bin in the *RollingUserClicks* column, the value is the aggregation of the user activities in the
// 28 days that preceded the bin. For example, if a user was active once on 2016-12-31 and then inactive throughout
// January, then the value will be 1 between 2016-12-31 -> 2017-01-28 and then 0s.
| extend RollingUserClicks=series_fir(UserClicks, moving_sum_filter, false)
// Use the zip() operator to pack the timestamp with the user activities per time bin.
| project User_AuthenticatedId=user_AuthenticatedId , RollingUserClicksByDay=zip(timestamp, RollingUserClicks)
// Transpose the table and create a separate row for each combination of user and time bin (1 day).
| mv-expand RollingUserClicksByDay
| extend Timestamp=todatetime(RollingUserClicksByDay[0])
// Mark the users that qualify according to min_activity.
| extend RollingActiveUsersByDay=iff(toint(RollingUserClicksByDay[1]) >= min_activity, 1, 0)
// And finally, count the number of users per time bin.
| summarize sum(RollingActiveUsersByDay) by Timestamp
// First 28 days contain partial data, so we filter them out.
| where Timestamp > starttime + 28d
// Render as timechart.
| render timechart
Çıktı aşağıda verilmiştir:
Aşağıdaki örnek, önceki sorguyu yeniden kullanılabilir bir işleve dönüştürür. Örnek daha sonra sıralı kullanıcı yapışkanlığını hesaplamak için sorguyu kullanır. Bu sorgudaki etkin bir kullanıcı, belirli bir günde en az bir kez kullanıma alma işlemi tamamlayan bir kullanıcı olarak tanımlanır.
let rollingDcount = (sliding_window_size: int, event_name:string)
{
let endtime = endofday(datetime(2017-03-01T00:00:00Z));
let window = 90d;
let starttime = endtime-window;
let interval = 1d;
let moving_sum_filter = toscalar(range x from 1 to sliding_window_size step 1 | extend v=1| summarize make_list(v));
let min_activity = 1;
customEvents
| where timestamp > starttime
| where customDimensions["sourceapp"]=="ai-loganalyticsui-prod"
| where (name == event_name)
| where user_AuthenticatedId <> ""
| make-series UserClicks=count() default=0 on timestamp
in range(starttime, endtime-1s, interval) by user_AuthenticatedId
| extend RollingUserClicks=fir(UserClicks, moving_sum_filter, false)
| project User_AuthenticatedId=user_AuthenticatedId , RollingUserClicksByDay=zip(timestamp, RollingUserClicks)
| mv-expand RollingUserClicksByDay
| extend Timestamp=todatetime(RollingUserClicksByDay[0])
| extend RollingActiveUsersByDay=iff(toint(RollingUserClicksByDay[1]) >= min_activity, 1, 0)
| summarize sum(RollingActiveUsersByDay) by Timestamp
| where Timestamp > starttime + 28d
};
// Use the moving_sum_filter with bin size of 28 to count MAU.
rollingDcount(28, "Checkout")
| join
(
// Use the moving_sum_filter with bin size of 1 to count DAU.
rollingDcount(1, "Checkout")
)
on Timestamp
| project sum_RollingActiveUsersByDay1 *1.0 / sum_RollingActiveUsersByDay, Timestamp
| render timechart
Çıktı aşağıda verilmiştir:
Regresyon analizi
Bu örnekte, yalnızca bir uygulamanın izleme günlüklerine dayalı olarak hizmet kesintileri için otomatik algılayıcının nasıl oluşturulacağı gösterilmektedir. Algılayıcı, uygulamadaki hata ve uyarı izlemelerinin göreli miktarında anormal, ani artışlar arar.
İzleme günlükleri verilerine göre hizmet durumunu değerlendirmek için iki teknik kullanılır:
- Yarı yapılandırılmış metin izleme günlüklerini pozitif ve negatif izleme çizgileri arasındaki oranı temsil eden bir ölçüme dönüştürmek için make-series kullanın.
- İki çizgili doğrusal regresyonla zaman serisi analizini kullanarak gelişmiş adım atlama algılaması için series_fit_2lines veseries_fit_line kullanın.
let startDate = startofday(datetime("2017-02-01"));
let endDate = startofday(datetime("2017-02-07"));
let minRsquare = 0.8; // Tune the sensitivity of the detection sensor. Values close to 1 indicate very low sensitivity.
// Count all Good (Verbose + Info) and Bad (Error + Fatal + Warning) traces, per day.
traces
| where timestamp > startDate and timestamp < endDate
| summarize
Verbose = countif(severityLevel == 0),
Info = countif(severityLevel == 1),
Warning = countif(severityLevel == 2),
Error = countif(severityLevel == 3),
Fatal = countif(severityLevel == 4) by bin(timestamp, 1d)
| extend Bad = (Error + Fatal + Warning), Good = (Verbose + Info)
// Determine the ratio of bad traces, from the total.
| extend Ratio = (todouble(Bad) / todouble(Good + Bad))*10000
| project timestamp , Ratio
// Create a time series.
| make-series RatioSeries=take_any(Ratio) default=0 on timestamp in range(startDate , endDate -1d, 1d) by 'TraceSeverity'
// Apply a 2-line regression to the time series.
| extend (RSquare2, SplitIdx, Variance2,RVariance2,LineFit2)=series_fit_2lines(RatioSeries)
// Find out if our 2-line is trending up or down.
| extend (Slope,Interception,RSquare,Variance,RVariance,LineFit)=series_fit_line(LineFit2)
// Check whether the line fit reaches the threshold, and if the spike represents an increase (rather than a decrease).
| project PatternMatch = iff(RSquare2 > minRsquare and Slope>0, "Spike detected", "No Match")
Sonraki adımlar
Kusto Sorgu Dili öğreticisini inceleyin.