Full Text Search
Text search (TextSearch) matches text within a single opened PDF document, either on a page or across a page range.
Full text search (FullTextSearch, namespace foxit::fts) works across multiple PDF files in a directory: first build or update an index database, then search by keyword and receive hits through a callback.
System requirements
- License: Requires a license key that includes the
Standardmodule - Languages: C, C++, Java, C#, Python, Objective-C, Node.js, Go
Capability overview
Typical full text search capabilities include:
- Build or update an index for PDFs in a specified directory (including subdirectories) (
StartUpdateIndex/UpdateIndexWithFilePath) - Search indexed files by keyword (
SearchOf) and receive hit information viaSearchCallback - Ignore whitespace between characters in the pattern string during search (
SetIgnoreSpace) - Cooperative cancellation during search (
SearchCallback::NeedToCancel)
Ignore-whitespace and cooperative cancellation are available starting in 12.0. For a complete runnable sample, see examples/simple_demo/fulltextsearch in the product package.
Basic workflow
- Construct
FullTextSearch. Optionally callSetDataBasePathto set the index database path (effective before the first indexing run; if unset, the default may befts.dbnext to the application). - Use
DocumentsSourceto specify the directory to index, then callStartUpdateIndex(progressive) orUpdateIndexWithFilePathfor a single file. - Implement
SearchCallback: handle hits inRetrieveSearchResult, and implementNeedToCancel. - Optionally call
SetIgnoreSpace, then callSearchOfto run the search.
Ignore whitespace in the pattern
Starting in 12.0, FullTextSearch::SetIgnoreSpace controls whether matching ignores whitespace between characters in the pattern string (spaces, tabs, newlines, and so on). It is off by default; when enabled, it takes effect immediately, without rebuilding the index, and does not change existing index content.
c++
full_text_search.SetIgnoreSpace(true); // default falsejava
search.setIgnoreSpace(true); // default falsecsharp
full_text_search.SetIgnoreSpace(true); // default falsepy
full_text_search.SetIgnoreSpace(True) # default Falsejs
full_text_search.SetIgnoreSpace(true); // default falsego
fullTextSearch.SetIgnoreSpace(true) // default falseSearch cancellation
Starting in 12.0, SearchCallback provides NeedToCancel so the host can request cancellation during search: return true to cancel, or false to continue. Earlier versions do not have this method. Existing custom callbacks must implement it, or the project will fail to compile or load. Return “continue” when cancellation is not needed.
| Language | Implement from 12.0 |
|---|---|
| C++ | virtual bool NeedToCancel() = 0; |
| C | FS_BOOL (*NeedToCancel)(void* user_data); |
| Java | boolean needToCancel() |
| C# | override bool NeedToCancel() |
| Python | def NeedToCancel(self, *args) |
| Node.js | NeedToCancel() |
| Go | func (cb ...) NeedToCancel() bool |
| Objective-C | -(BOOL)needToCancel |
The following sample demonstrates: build index → (optional) ignore whitespace → search, with a NeedToCancel implementation. For a complete runnable sample, see examples/simple_demo/fulltextsearch in the product package.
c++
#include "include/common/fs_common.h"
#include "include/fts/fs_fulltextsearch.h"
using namespace foxit;
using namespace foxit::common;
using namespace foxit::fts;
class SearchCallbackImp : public SearchCallback {
public:
virtual void Release() override { delete this; }
virtual bool NeedToCancel() override { return false; }
virtual int RetrieveSearchResult(const wchar_t* file_path, int page_index,
const WString& match_result,
int match_start_text_index, int match_end_text_index,
const WString& sentence,
int sentence_start_text_index,
int sentence_end_text_index) override {
// Handle the search hit.
return 0;
}
};
// Assume Library::Initialize has already been called.
FullTextSearch full_text_search;
full_text_search.SetDataBasePath("./search.db");
DocumentsSource docs_source("./pdf_folder");
Progressive search_progress = full_text_search.StartUpdateIndex(docs_source, NULL, false);
int state = Progressive::e_ToBeContinued;
while (state == Progressive::e_ToBeContinued) {
state = search_progress.Continue();
}
full_text_search.SetIgnoreSpace(true);
SearchCallbackImp* search_callback = new SearchCallbackImp();
full_text_search.SearchOf("Foxit", FullTextSearch::e_RankHitCountASC, search_callback);C
#include "include/fs_basictypes_c.h"
#include "include/fs_common_c.h"
#include "include/fs_fulltextsearch_c.h"
...
FS_BOOL gNeedToCancel(void* user_data) {
return FALSE; // Return FALSE when cancellation is not needed
}
int gRetrieveSearchResult(void* user_data, const wchar_t* file_path, int page_index,
const wchar_t* match_result, int match_start_text_index,
int match_end_text_index, const wchar_t* sentence,
int sentence_start_text_index, int sentence_end_text_index) {
// Handle the search hit.
return 0;
}
// Assume FSDK_Library_Initialize has already been called.
FS_FULLTEXTSEARCH_HANDLE full_text_search = NULL;
FSDK_FullTextSearch_Create(&full_text_search);
FSDK_FullTextSearch_SetDataBasePath(full_text_search, "./search.db");
FS_DOCUMENTSSOURCE_HANDLE docs_source = NULL;
FSDK_DocumentsSource_Create("./pdf_folder", &docs_source);
FS_PROGRESSIVE_HANDLE search_progress = NULL;
FS_PROGRESSIVESTATE state = e_FSToBeContinued;
FSDK_FullTextSearch_StartUpdateIndex(full_text_search, docs_source, NULL, FALSE, &search_progress);
while (state == e_FSToBeContinued) {
FSDK_Progressive_Continue(search_progress, &state);
}
FSSearchCallback* search_callback = (FSSearchCallback*)malloc(sizeof(FSSearchCallback));
search_callback->user_data = search_callback;
search_callback->Release = gRelease;
search_callback->RetrieveSearchResult = gRetrieveSearchResult;
search_callback->NeedToCancel = gNeedToCancel;
FS_BOOL return_value = FALSE;
FSDK_FullTextSearch_SearchOf(full_text_search, "Foxit", e_FSRankHitCountASC, search_callback, &return_value);java
import com.foxit.sdk.common.*;
import com.foxit.sdk.fts.*;
class MySearchCallback extends SearchCallback {
@Override
public void release() {}
@Override
public boolean needToCancel() {
return false; // Return false when cancellation is not needed
}
@Override
public int retrieveSearchResult(String filePath, int pageIndex, String matchResult,
int matchStartTextIndex, int matchEndTextIndex,
String sentence, int sentenceStartTextIndex,
int sentenceEndTextIndex) {
// Handle the search hit.
return 0;
}
}
// Assume Library.initialize has already been called.
FullTextSearch search = new FullTextSearch();
search.setDataBasePath("./search.db");
DocumentsSource source = new DocumentsSource("./pdf_folder");
Progressive progressive = search.startUpdateIndex(source, null, false);
int state = Progressive.e_ToBeContinued;
while (state == Progressive.e_ToBeContinued) {
state = progressive.resume();
}
search.setIgnoreSpace(true);
MySearchCallback searchCallback = new MySearchCallback();
search.searchOf("Foxit", FullTextSearch.e_RankHitCountASC, searchCallback);csharp
using foxit.common;
using foxit.fts;
public class SearchCallbackImp : SearchCallback
{
public override void Release() {}
public override bool NeedToCancel()
{
return false; // Return false when cancellation is not needed
}
public override int RetrieveSearchResult(string file_path, int page_index, string match_result,
int match_start_text_index, int match_end_text_index, string sentence,
int sentence_start_text_index, int sentence_end_text_index)
{
// Handle the search hit.
return 0;
}
}
// Assume Library.Initialize has already been called.
using (FullTextSearch full_text_search = new FullTextSearch())
{
full_text_search.SetDataBasePath("./search.db");
using (DocumentsSource docs_source = new DocumentsSource("./pdf_folder"))
{
Progressive search_progress = full_text_search.StartUpdateIndex(docs_source, null, false);
Progressive.State state = Progressive.State.e_ToBeContinued;
while (state == Progressive.State.e_ToBeContinued)
{
state = search_progress.Continue();
}
full_text_search.SetIgnoreSpace(true);
using (SearchCallbackImp searchCallback = new SearchCallbackImp())
{
full_text_search.SearchOf("Foxit", FullTextSearch.RankMode.e_RankHitCountASC, searchCallback);
}
}
}py
from FoxitPDFSDKPython3 import *
class SearchCallbackImp(SearchCallback):
def Release(self, *args):
pass
def NeedToCancel(self, *args):
return False # Return False when cancellation is not needed
def RetrieveSearchResult(self, *args):
# Handle the search hit.
return 0
# Assume Library.Initialize has already been called.
full_text_search = FullTextSearch()
full_text_search.SetDataBasePath("./search.db")
docs_source = DocumentsSource("./pdf_folder")
search_progress = full_text_search.StartUpdateIndex(docs_source, None, False)
state = Progressive.e_ToBeContinued
while state == Progressive.e_ToBeContinued:
state = search_progress.Continue()
full_text_search.SetIgnoreSpace(True)
searchCallback = SearchCallbackImp()
full_text_search.SearchOf("Foxit", FullTextSearch.e_RankHitCountASC, searchCallback)objc
@interface MySearchCallback : NSObject<FSSearchCallback>
@end
@implementation MySearchCallback
-(BOOL)needToCancel {
return NO; // Return NO when cancellation is not needed
}
-(int)retrieveSearchResult:(NSString *)file_path page_index:(int)page_index
match_result:(NSString *)match_result
match_start_text_index:(int)match_start_text_index
match_end_text_index:(int)match_end_text_index
sentence:(NSString *)sentence
match_sentence_start_text_index:(int)match_sentence_start_text_index
match_sentence_end_text_index:(int)match_sentence_end_text_index {
// Handle the search hit.
return 0;
}
@end
// Assume [FSLibrary initialize:sn key:key] has already been called.
FSFullTextSearch* fulltextsearch = [[FSFullTextSearch alloc] init];
[fulltextsearch setDataBasePath:@"./search.db"];
FSDocumentsSource* docs_source = [[FSDocumentsSource alloc] initWithDirectory:@"./pdf_folder"];
FSProgressive* search_progress = [fulltextsearch startUpdateIndex:docs_source pause:nil reupdate:NO];
FSProgressiveState state = FSProgressiveStateToBeContinued;
while (state == FSProgressiveStateToBeContinued) {
state = [search_progress continue];
}
MySearchCallback* searchCallback = [[MySearchCallback alloc] init];
[fulltextsearch searchOf:@"Foxit" rank_mode:FSFullTextSearchRankHitCountASC callback:searchCallback];js
const FSDK = require("@foxitsoftware/foxit-pdf-sdk-node");
class SearchCallbackImp {
Release() {}
NeedToCancel() {
return false; // Return false when cancellation is not needed
}
RetrieveSearchResult(filePath, pageIndex, matchResult, matchStartTextIndex,
matchEndTextIndex, sentence, sentenceStartTextIndex,
sentenceEndTextIndex) {
// Handle the search hit.
return 0;
}
}
// Assume FSDK.Library.Initialize has already been called.
let full_text_search = new FSDK.FullTextSearch();
full_text_search.SetDataBasePath("./search.db");
let docs_source = new FSDK.DocumentsSource("./pdf_folder");
let search_progress = full_text_search.StartUpdateIndex(docs_source, null, false);
let state = FSDK.Progressive.e_ToBeContinued;
while (state == FSDK.Progressive.e_ToBeContinued) {
state = search_progress.Continue();
}
full_text_search.SetIgnoreSpace(true);
let callback = new SearchCallbackImp();
let search_callback = new FSDK.SearchCallback(callback);
full_text_search.SearchOf("Foxit", FSDK.FullTextSearch.e_RankHitCountASC, search_callback);go
type SearchCallbackImp struct {
fsdk.SearchCallback
}
func (cb SearchCallbackImp) Release() {}
func (cb SearchCallbackImp) NeedToCancel() bool {
return false // Return false when cancellation is not needed
}
func (cb SearchCallbackImp) RetrieveSearchResult(filePath string, pageIndex int, matchResult string,
matchStartTextIndex, matchEndTextIndex int, sentence string,
sentenceStartTextIndex, sentenceEndTextIndex int) int {
// Handle the search hit.
return 0
}
// Assume fsdk.LibraryInitialize has already been called.
fullTextSearch := fsdk.NewFullTextSearch()
defer fsdk.DeleteFullTextSearch(fullTextSearch)
fullTextSearch.SetDataBasePath("./search.db")
docsSource := fsdk.NewDocumentsSource("./pdf_folder")
defer fsdk.DeleteDocumentsSource(docsSource)
searchProgress := fullTextSearch.StartUpdateIndex(docsSource, nil, false)
state := fsdk.ProgressiveE_ToBeContinued
for state == fsdk.ProgressiveE_ToBeContinued {
state = searchProgress.Continue()
}
fullTextSearch.SetIgnoreSpace(true)
searchCallback := SearchCallbackImp{}
searchCallback_ := fsdk.NewDirectorSearchCallback(searchCallback)
fullTextSearch.SearchOf("Foxit", fsdk.FullTextSearchE_RankHitCountASC, searchCallback_)If your application already subclasses SearchCallback in an earlier version, see the signature table in Search cancellation above for compile-time and implementation requirements when upgrading to 12.0 or later.