About File Metadata Queries



File metadata 는 일부 응용 프로그램 개발을 하는데 있어서, 파일이나 파일 시스템에 해당하는 데이터 기반으로 파일을 찾는 인터페이스를 제공해 줍니다. 응용 프로그램이 요구하는 검색 결과의 레벨은 어떤 API 를 사용하느냐에 따라 달라집니다.


여러분의 Mac OS X 응용프로그램에서 메타데이터를 사용하는 가장 간단한 방법은 Spotlight 검색창을 사용하는 것입니다. API 를 이용하면, 옵션으로 검색 문자열을 입력받는 Spotlight 검색창을 응용 프로그램에 삽입할 수 있습니다. 검색 결과는 곧바로 사용자에게 보여지며, 응용 프로그램에서 이 결과값을 사용할 수는 없습니다. 여러분의 응용 프로그램이 검색을 지향하지 않고, 단지 사용자가 Spotlight 를 통해 검색할 수 있는 방식을 간단히 제공해 주기 위한 경우라면, 이 방식이 적합 합니다.


응용 프로그램에서 질의를 만들고, 결과값을 사용해야 하는 경우라면, 이에 적합한 두 가지 API 가 있습니다.  MDQuery 라고 하는 Metadata 프레임워크는 저급레벨(low-level)의 질의 API 입니다. 이것은 응용 프로그램이 메타 데이터 값을 기반으로 파일을 검색할 수 있도록 해 줍니다.  MDQuery 는 전체적으로 사용자 설정이 가능하며,  동기나 비동기로 질의를 수행 할 수 있습니다. 또한 검색 결과의 응답 주기를 어떻게 할 것인지에 대한 미세한 설정까지도 제공합니다.


Cocoa 프레임워크의  NSMetadataQuery  클래스는  MDQuery  API 에 대한 고급레벨(high-level)의 Objective-C 인터페이스를 제공합니다. 이 클래스는  NSPredicate 클래스의 일부분(subset)을 사용하여 질의를 만들고, 비동기로 질의를 수행 할 수 있도록 해 줍니다.  NSMetadataQuery  클래스는 다중 하위 카테고리에서(multiple subcategories) 결과값을 그룹으로 묶는 것을 가능하게 해 줍니다.  NSMetadataQuery  는 비동기 질의는 지원하지 않으며, 데이타가 수집되었음을 알리는 업데이트 알림을 최소로 제공합니다. Mac OS X 의  NSMetadataQuery  는 별도의 접합코드(glue code) 작성 없이도 결과값을 표시할 수 있는, Cocoa 바인딩을 제공합니다. 


Note: iOS 는 오로지 메타 데이터 검색을 위한 Objective-C 인터페이스만 제공합니다. C 버젼의 프로시저는 Mac OS X 에서만 제공합니다.







Searching File Metadata with NSMetadataQuery



여러분의 응용 프로그램에서 Spotlight 메타 데이터를 검색하기 위해서는, Foundation 프레임워크에서 제공하는 NSMetadataQuery 클래스를 사용해서 질의(query)를 만들어야만 합니다. 질의(query)는 두 가지 모드로 동작 가능합니다. 하나는 비동기 모드이고, 다른 하나는 실시간 업데이트 비동기(asynchronous with live updates) 모드입니다. 전자는 초기 검색시 존재하는 파일에 대한 간단히 검색을 수행합니다. 후자는 계속해서 검색을 합니다. 검색 파라미터에 대한 업데이트가 모두 이루어 지거나, 더 이상 업데이트 할 데이터가 없을 때까지, 업데이트를 계속 합니다.


다음은 비동기 메타 데이터 질의가 수행되는 4 단계입니다.

  • 검색을 정의하고 초기화
  • 검색 시작
  • 알림 묶음을 수신
  • 완료 알림을 수신 대기
  • 질의 중지
  • 결과 처리


실시간 비동기 Spotlight 질의는 응용 프로그램이 특정 영역에 대해서 갑작스런 변화를 모니터링 할 수 있도록 해 줍니다. 코드의 유일한 중요한 차이점은 쿼리를 중지하는 것보다, 결과를 처리하는 동안 간단하게 쿼리를 중지하고 처리가 완료되면 검색을 다시 시작한다는 것입니다.



Creating a Static File Metadata Search



정적 Spotlight 검색은 간단한 검색입니다. 결과를 리턴하고 종료 됩니다. 이것은 변화를 감지(“Creating a Live Search.” 에서 다루고 있는 실시간 검색을 통해 가능한)하지 않는 1회성 검색을 위해 만들어진 것입니다.



검색 정의하기


질의를 생성하는 첫번째 단계는 원하는 검색 결과를 리턴하도록 검색 표현식(search expression)을 정의하는 것입니다. 만약 질의를 위해서  MDMetadataQuery  를 사용한다면,  “File Metadata Query Expression Syntax.”  에 나와있는 문법을 사용해서 검색 표현식 선언(search expression predicate)를 만들어야 합니다. 통지를 반드시 등록해서 데이터 묶음(batch)이 리턴되고 초기 검색이 완료었을 때, 알림을 전달 받을 수 있도록 해야 합니다. 또한 선택적으로 영역과 정렬, 델리게이터를 등록 할 수도 있습니다.





검색 질의 설정하기


검색 술부(search predicate)를 만들기 위해서는  “File Metadata Query Expression Syntax.”  에 설명되어 있는 문법을 사용하면 됩니다. 검색 가능한 속성은  File Metadata Attributes Reference 에 정의되어 있습니다. 속성 참조에는 유효한 메타 데이터 키값과 속성 검색시 제공해야 하는 데이터 타입(문자열, 숫자, 문자열의 배열, 날짜, Uniform Type 식별자 등)에 대해서 나와 있습니다.





정렬 방식 설정하기


NSMetadataQuery 를 사용하면, 정렬 표식자의 배열을 제공함으로써 결과에 대한 정렬 방식을 명시할 수 있습니다. 정렬은 리턴된  NSMetadataItem  객체 각각에 대한 메타데이터 속성 키를 기반으로 합니다.





검색 영역 제한하기


응용 프로그램에서 수집된 검색 결과를 명시된 검색 영역으로 제한합니다. 검색 영역은 미리 정의된 위치 정수(location constants), URL, 디렉토리 경로의 배열 형태로 질의에 전달 됩니다. 미리 정의된 위치 정수를 사용하면, 사용자 홈 디렉토리, 로컬에 마운트된 볼륨과 사용자 홈 디렉토리, 원격 마운트된 볼륨들과 같이 질의를 제한할 때 편리합니다.


메타 데이터 질의가 파일을 검색할 때, 명시하는 검색 영역. 표 2-1 은 유효한 영역 목록입니다.


표 2-1  지원되는 검색 영역

  영역 정수

 지원하는 운영체제 

 설명 

  NSMetadataQueryUbiquitousDocumentsScope   iOS and Mac OS X

응용 프로그램의 iCloud 컨테이너 디렉토리에 있는 문서 디렉토리의 모든 파일에서 검색

  NSMetadataQueryUbiquitousDataScope  iOS and Mac OS X

응용 프로그램의 iCloud 컨테이너 디렉토리에 있는 문서 디렉토리에 존재하지 않는 모든 파일에서 검색

  NSMetadataQueryNetworkScope  Mac OS X 사용자 마운트 된 원격 볼륨에서 검색 
  NSMetadataQueryLocalComputerScope  Mac OS X

사용자 홈 디렉토리를 포함한 로컬 마운트된 볼륨에서 검색. 사용자 홈 디렉토리가 리모트 볼륨이더라도 검색함.

  NSMetadataQueryUserHomeScope  Mac OS X 사용자 홈 디렉토리에서 검색 




검색 영역은 영억 정수의 배열로 명시됩니다.




Note: Mac OS X 에서 개발할 때 반드시 염두에 두어야 할 것이 있습니다. file-system 메타 데이터 모든 볼륨에서 유효하지만, 다른 메타 데이터 속성들은 그렇지 않습니다. CD, DVD, 디스크 이미지, 시스템 디렉토리는 Spotlight 에 의해서 index 되지 않습니다.

사용자는 Spotlight 설정을 사용하여 리턴된 결과에서 특정 디렉토리나 문서 타입을 제외시킬 수 있습니다. iOS 에서는 응용 프로그램 설정에 있는 General -> Spotlight Search 옵션을 사용하면, 검색 결과에서 문서 타입을 제거 시킬 수 있습니다.




검색 실행하기


질의 객체를 한 번 생성하고 설정하고 나면, 질의를 실행시킬 수 있습니다. 실행되는 동안, 질의는 형식적으로 두 가지 단계를 거치게 됩니다. 초기 결과를 수집하는 단계와 실시간 업데이트 단계입니다.


초기 결과를 수집하는 단계에서는, Spotlight system store 에 있는 검색 표현식에 일치하는 파일들을 찾습니다. 질의는 NSMetadataQueryDidUpdateNotification 를 사용해서, 묶음 형태로 리턴된 결과를 통지합니다. 이것은 검색 진행상황을 나타내는데 유용한데, 단일 질의에서보다 실시간 검색에서 훨씬 더 유용합니다.


질의는 초기 결과수집 단계가 완료되면, 응용 프로그램에게 NSMetadataQueryDidFinishGatheringNotification 알림을 전달합니다.





리턴된 결과에 접근하기


응용 프로그램에서 리턴된 결과를 사용하기 전에, 반드시 질의를 먼저 중지시켜야 합니다. 초기 수집 단계나 라이브 업데이트 단계에 있을 때, 업데이트가 되지 않도록 할 수 있습니다.


응용 프로그램에서는  NSMetadataQuery  의 인스턴스 메소드인  resultCount 를 통해서, 리턴되는 결과의 갯수를 결정 할 수 있습니다. 응용 프로그램은 인덱스된 위치를 사용하여, 개별 결과 아이템을 엑세스 합니다.  오히려  results  를 탐색하는 것보다(Cocoa 바인딩과 함께 사용하기 위해서),  resultAtIndex: 메소드를 사용해서 원하는 인덱스의 결과 아이템을 요청하는것이 더 좋습니다.


결과 아이템은  NSMetadataItem 타입의 객체 인스턴스로 리턴됩니다. 각각의 객체는 파일에 대한 메타 데이터 속성을 담고 있습니다. 응용 프로그램에서는 이들 아이템에 대해서,  valueForAttribute: 메세지에 원하는 메타 데이터 속성 이름을 전달함으로써, 메타 데이터 속성을 얻을 수 있습니다.





정적 검색 완료


“Creating a Static File Metadata Search” 는 정적 검색을 구현하는데 필요한 코드를 보여 줍니다.


Listing 2-1 Spotlight 정적 검색 구현


// Initialize Search Method
- (void)initiateSearch
{
    // Create the metadata query instance. The metadataSearch @property is
    // declared as retain
    self.metadataSearch=[[[NSMetadataQuery alloc] init] autorelease];
 
    // Register the notifications for batch and completion updates
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(queryDidUpdate:)
                                                 name:NSMetadataQueryDidUpdateNotification
                                               object:metadataSearch];
 
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(initalGatherComplete:)
                                                 name:NSMetadataQueryDidFinishGatheringNotification
                                               object:metadataSearch];
 
    // Configure the search predicate to find all images using the
    // public.image UTI
    NSPredicate *searchPredicate;
    searchPredicate=[NSPredicate predicateWithFormat:@"kMDItemContentTypeTree == 'public.image'"];
    [metadataSearch setPredicate:searchPredicate];
 
    // Set the search scope. In this case it will search the User's home directory
    // and the iCloud documents area
    NSArray *searchScopes;
    searchScopes=[NSArray arrayWithObjects:NSMetadataQueryUserHomeScope,
                  NSMetadataQueryUbiquitousDocumentsScope,nil];
    [metadataSearch setSearchScopes:searchScopes];
 
    // Configure the sorting of the results so it will order the results by the
    // display name
    NSSortDescriptor *sortKeys=[[[NSSortDescriptor alloc] initWithKey:(id)kMDItemDisplayName
                                                            ascending:YES] autorelease];
    [metadataSearch setSortDescriptors:[NSArray arrayWithObject:sortKeys]];
 
    // Begin the asynchronous query
    [metadataSearch startQuery];
 
}
 
// Method invoked when notifications of content batches have been received
- (void)queryDidUpdate:sender;
{
    NSLog(@"A data batch has been received");
}
 
 
// Method invoked when the initial query gathering is completed
- (void)initalGatherComplete:sender;
{
    // Stop the query, the single pass is completed.
    [metadataSearch stopQuery];
 
    // Process the content. In this case the application simply
    // iterates over the content, printing the display name key for
    // each image
    NSUInteger i=0;
    for (i=0; i < [metadataSearch resultCount]; i++) {
        NSMetadataItem *theResult = [metadataSearch resultAtIndex:i];
        NSString *displayName = [theResult valueForAttribute:(NSString *)kMDItemDisplayName];
        NSLog(@"result at %lu - %@",i,displayName);
    }
 
    // Remove the notifications to clean up after ourselves.
    // Also release the metadataQuery.
    // When the Query is removed the query results are also lost.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSMetadataQueryDidUpdateNotification
                                                  object:metadataSearch];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSMetadataQueryDidFinishGatheringNotification
                                                  object:metadataSearch];
    self.metadataQuery=nil;
}
 
@end







Creating a Live Search



라이브 검색은 단지 몇 개의 차이점을 제외한 동일한 검색을 통해 가상적으로 구성됩니다.



  • 업데이트 된 데이터를 엑세스 하기 전에,  disableUpdates 를 사용해서 질의를 중지시켜야 합니다.
  • 데이터는  queryDidUpdate: 메소드에서 몇 가지 형태(form)로 다루어집니다.
  • 검색을 계속 이어서 하도록  enableUpdates 를 사용하면, 질의는 다시 시작됩니다.






원문 : 

https://developer.apple.com/library/mac/#documentation/Carbon/Conceptual/SpotlightQuery/Concepts/Introduction.html#//apple_ref/doc/uid/TP40001841


https://developer.apple.com/library/mac/#documentation/Carbon/Conceptual/SpotlightQuery/Concepts/QueryingMetadata.html#//apple_ref/doc/uid/TP40001848-CJBEJBHH