Parse.com - 标记化数组字段中的子字符串搜索

时间:2014-07-19 14:06:35

标签: cocoa full-text-search parse-platform

我正在尝试一次在多个Parse类上实现复杂的全文搜索功能(class1上的query1或class2上的query2等)。根据{{​​3}}建议,最好对字符串进行标记,并在过滤后将其存储在可以利用whereKey:containsAllObjectsInArray:的数组中。

我的问题是:

  • 它搜索所有条款而不是任何
  • 它不搜索子串(例如Parse Array:["David", "Peter", "Vivien"],搜索vi返回0个对象)

截至目前,似乎唯一“体面”的方法是将类中的所有字符串连接成一个大字符串并使用whereKey:containsString:。我假设这将比标记化方法效率低。

你们有没有任何建议或建议如何开发 - 多个Parse类的高效和可扩展搜索?

谢谢!

2 个答案:

答案 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
                    // ....
                }
            }];
        }
    }
}];