我正在尝试一次在多个Parse类上实现复杂的全文搜索功能(class1上的query1或class2上的query2等)。根据{{3}}建议,最好对字符串进行标记,并在过滤后将其存储在可以利用whereKey:containsAllObjectsInArray:
的数组中。
我的问题是:
["David", "Peter", "Vivien"]
,搜索vi
返回0个对象)截至目前,似乎唯一“体面”的方法是将类中的所有字符串连接成一个大字符串并使用whereKey:containsString:
。我假设这将比标记化方法效率低。
你们有没有任何建议或建议如何开发 - 多个Parse类的高效和可扩展搜索?
谢谢!
答案 0 :(得分:0)
全文搜索是一个复杂的问题,许多数据库都有特殊支持,您可以在考虑成本后开启... Parse不支持全文搜索。
关于通过解析执行所需操作,whereKey:equalTo:
将用于查找其中一个项与所提供的字符串匹配的数组查找。
如果您想在任何地方进行匹配,可以使用OR query:
PFQuery *term1Query = [[PFQuery queryWithClassName:@"Class"] whereKey:@"terms" equalTo:@"David"];
PFQuery *term2Query = [[PFQuery queryWithClassName:@"Class"] whereKey:@"terms" equalTo:@"Peter"];
PFQuery *query = [PFQuery orQueryWithSubqueries:@[term1Query, term2Query]];
如果您希望能够匹配部分字符串,则需要稍微更改架构。创建一个名为“SearchToken”的新类,或者使用string类型的“token”列。
确保在创建/更新时始终强制使用小写。然后,您可以在相关类之间共享标记(例如,不要创建两个“david”标记,只需链接到新类的现有标记)。强制您的输入也为小写,因为所有字符串匹配都区分大小写。
您的“条款”列现在需要包含指针而不仅仅是单词。
您现在可以对“SearchToken”类进行查询,并在父类上使用whereKey:matchesQuery:
条件,例如:
PFQuery *tokenQuery = [PFQuery queryWithClassName:@"SearchToken"];
[tokenQuery whereKey:@"token" containsString:@"vi"];
PFQuery *mainQuery = [PFQuery queryWithClassName:@"MyClass"];
[mainQuery whereKey:@"terms" matchesQuery:tokenQuery];
您甚至可以使用上面的查询或完整匹配和部分匹配的混合。
请注意,令牌查询可能与许多行匹配,并受100行默认限制,如果您认为需要,请考虑设置更高的限制,最大值为1000.
关于创建SearchToken行,假设您已经从字符串中收集了令牌并强制它们为小写,现在有令牌链接/创建:
// these would be generated, manually creating for demonstration
NSArray *tokens = @[@"david", @"and", @"the", @"lion"];
PFQuery *existingTokens [PFQuery queryWithClassName:@"SearchToken"];
[existingTokens whereKey:@"token" containedIn:tokens];
// results of the above already exist, create new rows for the remainder
存在可能的竞争条件问题,其中另一个设备可能在运行查询后创建“david”标记。您可以找到一个查找重复项并删除重复行的作业,修复所有指针...尽管您希望处理竞争条件,因此逻辑可能是标记重复项并让所有其他查询搜索{{1然后找到所有指向指向重复行的行的记录,并将它们指向[query whereKeyDoesNotExist: @"duplicateOf"];
。一切都取决于你避免重复的重要性,也许这对你来说不是问题。
答案 1 :(得分:0)
我已成功实施搜索功能,只需进行少量修改。说服Parse执行全文搜索是非常昂贵的(保存:2个API调用:获取现有标记+保存新标记,搜索:1 +(1 * N):获取匹配搜索项的标记+ N ==没有可搜索对象)。 我想知道是否有更好的方法可以达到相同的结果,有人对如何提高成本有任何建议吗?
虽然保存与Timothy描述的完全相同,但检索如下:
// 1) check for sanitised terms in SearchToken class
// _marrInputTokens - mutable array of sanitised search terms
NSMutableArray *_marrInnerQueries = [[NSMutableArray alloc] init];
for(NSString *_token in _marrInputTokens)
{
PFQuery *_innerQuery = [PFQuery queryWithClassName:@"SearchToken"];
[_innerQuery whereKey:@"token" containsString:_token];
[_marrInnerQueries addObject:_innerQuery];
}
PFQuery *_pSearchTokenQuery = [PFQuery orQueryWithSubqueries:_marrInnerQueries];
[_pSearchTokenQuery setLimit:1000];
[_pSearchTokenQuery findObjectsInBackgroundWithBlock:^(NSArray *tokenObjects, NSError *error) {
if(error)
{
QLog([error localizedDescription]);
}
else
{
// 2) if not all search terms (even as substrings) were found in SearchToken, no need to search further
// as no object can meet the search criteria and we can save some calls
if([tokenObjects count] >= [_marrInputTokens count])
{
// 3) all search terms were found in SearchToken
// fetch all SearchableObject_1 corresponding objects
PFQuery *_pResultQuery = [PFQuery queryWithClassName:@"SearchableObject_1"];
// 4) need to make sure all tokens are conjugated with AND operator
for(PFObject *_tokenObject in _marrSearchTokenResults)
{
[_pResultQuery whereKey:@"searchIndex" equalTo:_tokenObject];
}
// 5) pagination (adding setSkip: for real pagination)
[_pResultQuery setLimit:PARSE_RESULT_LIMIT];
[_pResultQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if(error)
{
QLog([error localizedDescription]);
}
else
{
// 6) objects contains all matching entries for SearchableObject_1
// 7) nested additional SearchableObject_x searches
// ....
}
}];
}
}
}];