An open API service indexing awesome lists of open source software.

https://github.com/dagronf/dfsearchkit

Swift/Objective-C framework for macOS around Apple's SearchKit
https://github.com/dagronf/dfsearchkit

apple macos macosx search searchkit swift

Last synced: about 1 year ago
JSON representation

Swift/Objective-C framework for macOS around Apple's SearchKit

Awesome Lists containing this project

README

          

# DFSearchKit

A framework implementing a search index and summary generator using SKSearchKit for both Swift and Objective-C

![](https://img.shields.io/github/v/tag/dagronf/DFSearchKit) ![](https://img.shields.io/badge/macOS-10.11+-red) ![](https://img.shields.io/badge/Swift-5.0-orange.svg)
![](https://img.shields.io/badge/License-MIT-lightgrey) [![](https://img.shields.io/badge/pod-compatible-informational)](https://cocoapods.org) [![](https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat)](https://swift.org/package-manager)

## Why?

I was interesting in learning about SKSearchKit and wanted a nice simple object to abstract away some of the unpleasantries when dealing with a C-style interface in Swift using native Swift types.

## Usage

The base library is split into three classes and an async controller.

### Copy

Copy everything from the `DFSearchKit` sub-folder into your own project

### Cocoapods

Add the following to your `Podfiles` file

`pod 'DFSearchKit', :git => 'https://github.com/dagronf/DFSearchKit'`

### Swift Package Manager

Import via Xcode.

## Classes

### DFSearchIndex.Memory

A class inheriting from DFSearchIndex that implements an in-memory index. This index exists purely in memory, and will be destroyed when the index is deallocated.

```swift
// Create a new memory index using the default settings
guard let indexer = DFSearchIndex.Memory() else {
assert(false)
}

indexer.add(textURL: "doc-url://d1.txt", text: "This is my first document")

let fileURL = //
indexer.add(fileURL, mimeType: "application/pdf")

// ... add more documents

indexer.flush()

let searchresult = indexer.search("first")

// Do something with the search results

```

`DFSearchIndex.Memory` provides methods to get the raw index data for storing, and to load from data

##### Load from a raw Data object
```swift
let indexData = Data(...)
guard let indexer = DFSearchIndex.Memory(data: indexData) else {
assert(false)
}
```

##### Extract the raw Data object from the search index
```swift
let newIndexData = indexer.data()
```

### DFSearchIndex.File

A class inheriting from DFSearchIndex that allows the creation and use of an index on disk.

```swift
// Create a index on disk
let newFileURL = //
let createProperties = DSFSearchIndex.CreateProperties() // search index properties
guard let newIndex = DFSearchIndex.File(fileURL: newFileURL, properties: createProperties) else {
assert(false)
}

// Open a file index
let existingFileURL = //
guard let fileIndex = DFSearchIndex.File(fileURL: existingFileURL, writable: true) else {
assert(false)
}

let documentURL = URL(string: ("doc-url://d1.txt")!
fileIndex.add(documentURL, text: "This is my first document"))

let fileURL = //
fileIndex.add(fileURL, mimeType: "application/pdf")

// Flush the index so that it is updated for searching
fileIndex.flush()

// Perform a basic search for the work 'first'
var result = indexer.search("first")

fileIndex.save()
fileIndex.close()
```

### DFSearchIndex.AsyncController

`DFSearchIndex.AsyncController` is a simple controller that takes an index object, and provides a safe method for handling async requests.

For example, to add a number of files asynchronously

```swift
guard let searchIndex = DFSearchIndex.Memory() else {
assert(false)
}

let asyncController = DFSearchIndex.AsyncController(index: searchIndex, delegate: nil)

// Create a file task containing the URLs to be indexed
let addTask = DFSearchIndex.AsyncController.FileTask()

asyncController.addURLs(async: addTask, complete: { task in
//
})

...

// Create a file task containing the URLs to be removed

let removeTask = DFSearchIndex.AsyncController.FileTask()
asyncController.removeURLs(async: removeTask, complete: { task in
//
})

```
Internally the async controller uses an operation queue for handling requests.

## Searching

There are two methods for search

### Search all

The search all is available on the indexer object, and returns all the results it can get. As such, for large indexes this may take quite a while to return. It is provided mostly as a convenience function for small indexes.

```swift
guard let searchIndex = DFSearchIndex.Memory() else {
assert(false)
}

// Add some documents...
searchIndex.add(textURL: "doc-url://d1.txt", text: "This is my first document"))

// Flush the index
searchIndex.flush()

// Search for the word 'first'
let searchResult = indexer.search("first")
// searchResult.count == 1
// searchResult[0].url == firstURL
// searchResult[0].score == 1

searchIndex.save()
searchIndex.close()
```

### Progressive Search

For large indexes, the results may take quite a while to return. Thus, the progressive index is more useful by returning limited sets of results progressively, and can be used on a background thread (as SKSearchIndex is thread safe) to progressively retrieve results in another thread (for example)

```swift
/// ... load documents ...
let search = indexer.progressiveSearch(query: "dog")
var hasMoreResults = true
repeat {
var searchChunk = search.next(10)

// ... do something with searchChunk...

hasMoreResults = searchChunk.moreResults
}
while hasMoreResults
```

## Summary Generation

The `DFSearchIndex.Summarizer` class provides a wrapper around the `SKSummary` interface, providing text rankings and orderings.

```swift
let text = //