Performing a join using "contains"

%3CLINGO-SUB%20id%3D%22lingo-sub-2368275%22%20slang%3D%22en-US%22%3EPerforming%20a%20join%20using%20%22contains%22%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2368275%22%20slang%3D%22en-US%22%3E%3CP%3EI%20have%20two%20tables%20and%20Table%20%22A%22%20has%20a%20list%20of%20error%20messages%20while%20Table%20%22B%22%20has%20a%20list%20of%20keywords.%26nbsp%3B%20%26nbsp%3BIs%20there%20any%20way%20to%20return%20a%20list%20of%20those%20error%20messages%20from%20Table%20A%20that%20a%20contain%20a%20keyword%20from%20Table%20%22B%22.%26nbsp%3B%20Something%20like%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EA%20join%20B%20on%20%24left.ErrorMessage%20contains%20%24B.Keyword%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2369054%22%20slang%3D%22en-US%22%3ERe%3A%20Performing%20a%20join%20using%20%22contains%22%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2369054%22%20slang%3D%22en-US%22%3EI%20think%20the%20query%20made%20for%20Zscaler%20might%20do%20what%20you%20are%20looking%20for.%20Just%20replace%20the%20ThreatIntelligenceIndicator%20and%20Common%20SecurityLog%20tables%20with%20the%20fields%20you%20need%2C%20then%20project%20the%20matches.%20The%20query%20is%20projecting%20fields%20from%20each%20table.%20Let%20me%20know%20if%20you%20need%20a%20hand!%3CBR%20%2F%3E%3CBR%20%2F%3Elet%20dt_lookBack%20%3D%207d%3B%3CBR%20%2F%3Elet%20ioc_lookBack%20%3D%2014d%3B%3CBR%20%2F%3EThreatIntelligenceIndicator%3CBR%20%2F%3E%7C%20where%20TimeGenerated%20%26gt%3B%20ago(ioc_lookBack)%3CBR%20%2F%3E%7C%20where%20DomainName%20contains%20%22.%22%20and%20DomainName%20!contains%20%22.storage.googleapis.com%22%20and%20DomainName%20!contains%20%22.office.com%22%3CBR%20%2F%3E%7C%20join%20(%3CBR%20%2F%3ECommonSecurityLog%3CBR%20%2F%3E%7C%20where%20TimeGenerated%20%26gt%3B%20ago(dt_lookBack)%3CBR%20%2F%3E%7C%20where%20DestinationHostName%20contains%20(%22.%22)%3CBR%20%2F%3E%7C%20extend%20CommonSecurityLog_TimeGenerated%20%3D%20TimeGenerated%3CBR%20%2F%3E)%3CBR%20%2F%3Eon%20%24left.DomainName%20%3D%3D%20%24right.DestinationHostName%3CBR%20%2F%3E%7C%20project%20SourceUserName%2C%20DomainName%2C%20CommonSecurityLog_TimeGenerated%2C%20Description%2C%20Activity%3CBR%20%2F%3E%7C%20extend%20AccountCustomEntity%20%3D%20SourceUserName%3CBR%20%2F%3E%7C%20extend%20HostCustomEntity%20%3D%20DomainName%3CBR%20%2F%3E%7C%20extend%20URLCustomEntity%20%3D%20DomainName%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2369763%22%20slang%3D%22en-US%22%3ERe%3A%20Performing%20a%20join%20using%20%22contains%22%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2369763%22%20slang%3D%22en-US%22%3EIt%20is%20very%20close%20but%20in%20my%20case%20the%20%22.storage.googleapis.com%22%20and%20%22%2C.office.com%22%20would%20be%20coming%20from%20the%20other%20table%20(CommonSecurityLog%20in%20this%20example)%3C%2FLINGO-BODY%3E
Super Contributor

I have two tables and Table "A" has a list of error messages while Table "B" has a list of keywords.   Is there any way to return a list of those error messages from Table A that a contain a keyword from Table "B".  Something like:

 

A join B on $left.ErrorMessage contains $B.Keyword

 

4 Replies
I think the query made for Zscaler might do what you are looking for. Just replace the ThreatIntelligenceIndicator and Common SecurityLog tables with the fields you need, then project the matches. The query is projecting fields from each table. Let me know if you need a hand!

let dt_lookBack = 7d;
let ioc_lookBack = 14d;
ThreatIntelligenceIndicator
| where TimeGenerated > ago(ioc_lookBack)
| where DomainName contains "." and DomainName !contains ".storage.googleapis.com" and DomainName !contains ".office.com"
| join (
CommonSecurityLog
| where TimeGenerated > ago(dt_lookBack)
| where DestinationHostName contains (".")
| extend CommonSecurityLog_TimeGenerated = TimeGenerated
)
on $left.DomainName == $right.DestinationHostName
| project SourceUserName, DomainName, CommonSecurityLog_TimeGenerated, Description, Activity
| extend AccountCustomEntity = SourceUserName
| extend HostCustomEntity = DomainName
| extend URLCustomEntity = DomainName
It is very close but in my case the ".storage.googleapis.com" and ",.office.com" would be coming from the other table (CommonSecurityLog in this example)
Ok, I see now. You are looking for a way around the == only join. Searching each value from the left through the text blob on the right. Ooof... I will keep thining =)

@Gary Bushey I have it working but not sure if it is the best way to do it.   First, I add a dummy column to each table that contains the same value, then I do a full outer join on the two tables using those new columns.   Since I just need to get a count of the matching items I can do 

summarize countif(TableBcolumn contains TableAcolumn) by TableAcolumn