使用Examine搜索Microsoft Graph用户时的短语搜索异常问题
解决Examine多字段精确短语搜索问题
问题概述
使用Examine搜索Microsoft Graph用户列表时,执行短语搜索"Project Controller",返回结果包含所有含Project或Controller的记录,但实际需求是仅返回任意指定字段中包含完整短语的结果。目前实际只有14个用户的JobTitle为Project Controllers,但搜索返回了68条无关结果。
现有代码与生成查询分析
原始查询代码
public async Task<List<User>> Search(string query = "") { string[] terms = query.Split(' '); _allUsers = await GetAllUsers(); List<User> matchingUsers = new List<User>(); if (_examineManager.TryGetIndex("ColleaguesIndex", out _colleaguesIndex)) { var searchFields = new[] { "FirstName", "LastName", "DisplayName", "StreetAddress", "JobTitle", "Department", "BusinessUnit", "OfficeLocation", "City", "State", "PostalCode", "BusinessPhones", "MobilePhone", "CompanyName" }; var results = _colleaguesIndex.Searcher.CreateQuery(defaultOperation: BooleanOperation.Or) .GroupedOr(searchFields, query.MultipleCharacterWildcard()).Or() .GroupedOr(searchFields, query.Escape()).Or() .GroupedOr(searchFields, terms) .Execute(); var resultsID = results.Select(r => r.Id); matchingUsers = _allUsers.Where(u => resultsID.Contains(u.OnPremisesSamAccountName)).ToList(); } return matchingUsers; }
生成的查询语句
{ ( FirstName : project controller* LastName : project controller* DisplayName : project controller* StreetAddress : project controller* JobTitle : project controller* Department : project controller* BusinessUnit : project controller* OfficeLocation: project controller* City : project controller* State : project controller* PostalCode : project controller* BusinessPhones: project controller* MobilePhone : project controller* CompanyName : project controller* ) ( FirstName : "Project controller" LastName : "Project controller" DisplayName : "Project controller" StreetAddress : "Project controller" JobTitle : "Project controller" Department : "Project controller" BusinessUnit : "Project controller" OfficeLocation: "Project controller" City : "Project controller" State : "Project controller" PostalCode : "Project controller" BusinessPhones: "Project controller" MobilePhone : "Project controller" CompanyName : "Project controller" ) ( FirstName : project FirstName : controller LastName : project LastName : controller DisplayName : project DisplayName : controller StreetAddress : project StreetAddress : controller JobTitle : project JobTitle : controller Department : project Department : controller BusinessUnit : project BusinessUnit : controller OfficeLocation: project OfficeLocation: controller City : project City : controller State : project State : controller PostalCode : project PostalCode : controller BusinessPhones: project BusinessPhones: controller MobilePhone : project MobilePhone : controller CompanyName : project CompanyName : controller ) }
简化查询测试问题
将查询简化为仅保留精确短语搜索后:
var results = _colleaguesIndex.Searcher.CreateQuery().GroupedOr(searchFields, query.Escape()).Execute();
生成的Lucene查询为:
LuceneQuery: {+(FirstName:"Project Controller" LastName:"Project Controller" DisplayName:"Project Controller" StreetAddress:"Project Controller" JobTitle:"Project Controller" Department:"Project Controller" BusinessUnit:"Project Controller" OfficeLocation:"Project Controller" City:"Project Controller" State:"Project Controller" PostalCode:"Project Controller" BusinessPhones:"Project Controller" MobilePhone:"Project Controller" CompanyName:"Project Controller")}
该查询要求所有字段都匹配短语,因此返回0条结果,不符合需求。
问题根源
- 原始查询同时叠加了通配符模糊搜索、精确短语搜索、单词Or搜索,导致结果范围被无限制扩大,包含所有含任意单个关键词的记录。
- 简化查询未指定
defaultOperation为BooleanOperation.Or,默认采用And逻辑,要求所有字段必须同时匹配短语,显然不符合实际数据分布。 - 实际目标数据为复数形式
Project Controllers,而搜索词为单数Project Controller,即使逻辑正确也无法匹配到目标记录。
解决方案
核心修改思路
构造仅包含精确短语匹配的查询,指定任意一个搜索字段匹配短语即可命中,同时可选支持复数形式的通配符扩展。
修改后代码
public async Task<List<User>> Search(string query = "") { _allUsers = await GetAllUsers(); List<User> matchingUsers = new List<User>(); if (_examineManager.TryGetIndex("ColleaguesIndex", out _colleaguesIndex)) { var searchFields = new[] { "FirstName", "LastName", "DisplayName", "StreetAddress", "JobTitle", "Department", "BusinessUnit", "OfficeLocation", "City", "State", "PostalCode", "BusinessPhones", "MobilePhone", "CompanyName" }; // 构造精确短语查询,若需匹配复数形式(如Project Controllers),使用带通配符的短语 var searchPhrase = query.Contains(' ') ? $"\"{query}\"" : query; // 支持复数:var searchPhrase = query.Contains(' ') ? $"\"{query}*\"" : $"{query}*"; var results = _colleaguesIndex.Searcher.CreateQuery(defaultOperation: BooleanOperation.Or) .GroupedOr(searchFields, searchPhrase) .Execute(); var resultsID = results.Select(r => r.Id); matchingUsers = _allUsers.Where(u => resultsID.Contains(u.OnPremisesSamAccountName)).ToList(); } return matchingUsers; }
关键说明
- 指定布尔操作逻辑:通过
defaultOperation: BooleanOperation.Or确保查询逻辑为「任意字段匹配短语即可」。 - 精确短语构造:对含空格的查询用双引号包裹,生成Lucene的精确短语查询语法。
- 复数支持:若需匹配
Project Controllers这类复数形式,可在短语末尾添加通配符*,构造为"Project Controller*"。
验证结果
修改后执行"Project Controller"搜索(若启用通配符则匹配复数),将仅返回在指定字段中包含完整短语的用户,即预期的14条JobTitle为Project Controllers的记录。
内容的提问来源于stack exchange,提问作者s15199d
相关产品推荐
相关产品推荐

