SWISH-LIBRARY(1)
β¨ SWISH-LIBRARY(1) β¨
bestie, this is the SWISH-LIBRARY(1) page from the SWISH-E Documentation π Let's get into it π¦
π NAME π
SWISH-LIBRARY is the interface to the Swish-e C library πβ¨
πΈ OVERVIEW πΈ
okay so the C library is an interface to the Swish-e search code π«Ά It's basically how you embed Swish-e straight into your own apps. This API is based on Swish-e version 2.3 π
Note: This is a NEW API as of Swish-e version 2.3 π The C language interface changed, and so did the Perl interface to Swish-e. The new Perl interface is the SWISH::API module, and it's included with the Swish-e distribution. The old SWISHE perl module has been rewritten to work with the new API. The SWISHE perl module is no longer included with the Swish-e distribution, but you can download it from the Swish-e web site.
The big win with the library is that you can open the index file or files one time and then make tons of queries on that open index π§ This skips the startup time of forking and running the swish-e binary, plus the expensive step of opening the index file. Some benchmarks have shown a three fold increase in speed π₯
The downside is that your program now carries more code and data (the index tables can eat quite a bit of memory). Also, if a fatal error happens in swish, it will bring down your program π These are things to think about, especially if you're embedding swish into a web server like Apache, where there are many processes serving requests.
The best way to learn the library is to check out two files included with the Swish-e distribution that actually use it π
π§ src/libtest.c
This file gives a basic overview of linking a C program with the Swish-e library. It doesn't use every available function, but it's a great overview of building a C program with swish-e π
To build and run libtest, chdir to the src directory and run these commands:
$ make libtest
$ ./libtest [optional name of index file]
You'll be prompted for the search words. The default index used is index.swish-e. You can override this by placing a list of index files in a quote-protected string:
$ ./libtest 'index1 index2 index3'
π¦ perl/API.xs
The API.xs file is a Perl "xsub" interface to the C library, and it's part of the SWISH::API Perl module π It's an object-oriented interface to the Swish-e library, and it shows how the various search "objects" are created by C calls and how they get destroyed when they're no longer needed π«Ά
π οΈ Installing the Swish-e library π οΈ
The Swish-e library gets installed when you run make install while building Swish-e. No extra installation steps needed, slay β¨
The library is made up of a header file swish-e.h and a library libswish-e.*. Depending on your platform, that library can be either static or shared πΈ
π Library Overview π
When you first attach to an index file (or index files), you get back a "swish handle" π From the handle, you create one or more "search objects." These hold the parameters for querying the index, like the query string, sort order, search phrase delimiter, limit parameters, and HTML structure bits π
The "object" is really just a pointer to a C structure, but it's helpful to think of it as an object with data and functionality attached to it π§
The search object is what you use to query the index. A query returns a "results object." The results object holds the number of hits, the parsed query per index, and the result set. It also keeps track of your current position in the result set. You can "seek" to a specific record in the result set, which is super useful for showing a page of results π
Finally, a result object represents a single result from the result list. It gives you access to that result's properties, like file name, rank, etc. π
Beyond results, there are functions for accessing the header values stored in the index file, functions for checking and reporting errors, and a few utility functions π οΈ
π Available Functions π
Here's the list of available functions in the Swish-e C language API π
These functions (and typedefs) are defined in the swish-e.h header file. The common objects (e.g. structures) used are:
SW_HANDLE - swish handle that associates with an index file
SW_SEARCH - search "object" that holds search parameters
SW_RESULTS - results "object" that holds a result set
SW_RESULT - a single result used for accessing the result's properties
SW_FUZZYWORD - used for fuzzy (stemming) word conversion
π Searching
β¨ SwishInit
SW_HANDLE SwishInit(char *IndexFiles);
This function opens and reads the header info of the index files listed in the IndexFiles string. The string should be a space-separated list of index files π«Ά
SW_HANDLE myhandle;
myhandle = SwishInit("file1.idx");
Typically you'll open a handle at the beginning of your program and use it to make multiple queries on an index π
This function will always return a swish handle. You have to check for errors, and on error you need to free the memory used by the handle, or abort π
Here's an example of aborting:
SW_HANDLE swish_handle;
swish_handle = SwishInit("file1.idx file2.idx");
if ( SwishError( swish_handle ) )
SwishAbortLastError( swish_handle );
And here's an example of catching the error:
SW_HANDLE swish_handle;
swish_handle = SwishInit("file1.idx file2.idx");
if ( SwishError( swish_handle ) )
{
printf("Failed to connect to swish. %s\n", SwishErrorString( swish_handle ) );
SwishClose( swish_handle ); /* free the memory used */
return 0;
}
You can have more than one handle active at a time π¦
Swish-e won't tell you if the index file changes on disk (like after reindexing) π In a persistent environment (e.g. mod_perl), the calling program should check whether the index file has changed on disk. A common way to do this is to store the inode number before opening the index file(s), then stat the file name every so often and reopen the index files if the inode number changes.
β¨ SwishClose
void SwishClose(SW_HANDLE handle);
This function closes a Swish handle and frees its memory π§Ή Every swish handle should be freed when you're done searching the index. Forgetting to close the handle will cause a memory leak π
β¨ New_Search_Object
SW_SEARCH New_Search_Object(SW_HANDLE handle, const char *query);
Returns a new search "object" π The search object holds the parameters used for searching an index. A single search object can be used to query the index multiple times. The settings listed below are "sticky," meaning they stay set on the search object until you change them π
β¨ SwishGetStructure
int SwishGetStructure( SW_SEARCH srch );
Returns the "structure" flag of the search object you pass in, or 0 if the search object is NULL π
β¨ SwishPhraseDelimiter
void SwishPhraseDelimiter( SW_SEARCH srch, char delimiter );
Sets the phrase delimiter character. The default is double-quotes π
β¨ SwishGetPhraseDelimiter
char SwishGetPhraseDelimiter( SW_SEARCH srch );
Returns the phrase delimiter character used in the search object, or 0 if the search object is NULL π§
β¨ SwishSetStructure
void SwishSetStructure( SW_SEARCH srch, int structure );
Sets the "structure" flag in the search object. The structure flag is used to limit searches to parts of HTML files (like the title or headers). The default is to not limit. This gives you the functionality of the -H command line switch π«Ά
β¨ SwishPhraseDelimiter
void SwishPhraseDelimiter( SW_SEARCH srch, char delimiter );
Sets the phrase delimiter character. The default is double-quotes π
β¨ SwishSetSort
void SwishSetSort( SW_SEARCH srch, char *sort );
Sets the sort order of the results. This is the same as the -s switch used with the swish-e binary π₯
β¨ SwishSetQuery
void SwishSetQuery( SW_SEARCH srch, char *query );
Sets the query string in the search object. You usually don't need this, since you can set it when creating the search object or when executing a query π
β¨ SwishSetSearchLimit
void SwishSetSearchLimit( SW_SEARCH srch, char *propertyname, char *low,
char *hi);
Sets the limit parameters for a search. It does the same thing as the -L command line switch πΈ You can specify a range of property values that search results must fall within. You can call SwishSetSearchLimit() only one time for each property, but you can set limits on more than one property at a time π¦
Unlike the other settings on the search object, once you've run a query on the search object, you must call SwishResetSearchLimit() to change or clear the limit parameters π
β¨ SwishResetSearchLimit
void SwishResetSearchLimit( SW_SEARCH srch );
Resets the limits that were set on a search object by SwishSetSearchLimit() π§Ή
β¨ Free_Search_Object
void Free_Search_Object( SW_SEARCH srch );
Frees the search object. This must be called when you're done with the search object π§Ή You can usually reuse a search object for multiple queries, so you'd typically call this right before calling SwishClose() π
You can free the search object before freeing any generated results objects π
β¨ SwishExecute
SW_RESULTS SwishExecute( SW_SEARCH search, const char *query);
Searches the index or indexes based on the parameters in the search object. Returns a results object π See below for functions that access the data stored in the results object π§
You should always check for errors after calling SwishExecute() π«Ά
β¨ SwishQuery
SW_RESULTS SwishQuery(SW_HANDLE, const char *words );
This is a short-cut function that skips creating a search object (actually, it skips the need to create and free one) β‘ It only lets you pass in a query string. Other search parameters can't be set. The results are sorted by rank π
You should always check for errors after calling SwishQuery() π
π Reading Results
β¨ SwishHits
int SwishHits( SW_RESULTS results );
Returns the number of results in the results object π’
β¨ SwishParsedWords
SWISH_HEADER_VALUE SwishParsedWords( SW_RESULTS, const char *index_name
);
Returns the tokenized query. Words are split by WordCharacters, and stopwords are removed π The parsed words are super useful for highlighting search terms in your program π
The "index_name" is the name of the index supplied in the SwishInit() function call π
Returns a SWISH_HEADER_VALUE union of type SWISH_LIST, which is a char **. Check out src/libtest.c for an example of accessing the strings in this list. In general, you can cast this to a (char **) π
β¨ SwishRemovedStopwords
SWISH_HEADER_VALUE SwishRemovedStopwords( SW_RESULTS, const char
*index_name );
Returns a list of the stopwords removed from the input query π¦
Okay so, picking up right where we left off bestie π Here's the lowdown on how to pull results and their stuff out of the index. π₯
int SwishSeekResult( SW_RESULTS, int position );
Okay so this one sets your current seek position in the results list π¦ Position zero is the first record, which is different from -b, where one is the first result. Lowkey confusing, but you'll get used to it. π
It gives back the position, or a negative number if something goes wrong. β¨
SW_RESULT SwishNextResult( SW_RESULTS );
This one grabs the next result π If there aren't any more results, you get NULL back. Literally no cleanup needed for the result object after you're done with it π«Ά (unlike the swish handle, search object, and results object, which you DO have to free).
const char *SwishResultPropertyStr(SW_RESULT, char *propertyname);
Honestly this one is mostly for testing, because it gives back weird stuff when things go wrong π It aborts if you pass it a NULL SW_RESULT object, so don't do that bestie π
When it works, it hands you back the string value of the property you asked for. If the current result doesn't have that property assigned, you get the empty string "" πΈ If the property name is invalid (aka it's not defined in the index), you get the string "(null)" and an error gets set, which you can check for with SwishError() (see below) π
The string doesn't need freeing, but it's only valid for the current result, so if you want to keep it you gotta copy it locally π§
Dates get formatted with the hard-coded format string "%Y-%m-%d %H:%M:%S" in localtime. Very specific, very iconic π
unsigned long SwishResultPropertyULong(SW_RESULT r, char *propertyname);
This returns a numeric property as an unsigned long π’ Numeric properties cover both the PropertyNamesNumeric and PropertyNamesDate types, and dates come back as a unix timestamp, as reported by the system when the index was created β°
If you pass in a NULL SW_RESULT object, swish-e will abort. No result object means swish-e can't set any error codes, so it has nothing to tell you π
On error you get UMAX_LONG back. This is commonly defined in limits.h π Check SwishError() (see below) to find out what kind of error happened.
- If
SwishError()returns false (zero), it just means this result has no data for that property π - If
SwishError()returns true (non-zero), then either the property name is invalid, or the property isn't numeric (or date). For example, it might be a string property π
When SwishError() is true, check the section below to see how to get the specific error message π«Ά
PropValue *getResultPropValue (SW_RESULT r, char *propertyname, int ID
);
This is a low-level function that fetches a property no matter what type it is, and honestly it's probably the best function for accessing properties π
Like the others, it aborts if you give it a NULL SW_RESULT object β οΈ propertyname is the name of the property. ID is the property's id number, if you already know it. You don't usually need ID in the API. Its whole purpose is to avoid looking up the property ID for every single result you display π¦
The returned PropValue is a structure with a flag that tells you the type, plus a union that holds the actual value. The flags and the structure are defined in swish-e.h π
Here's the important part bestie: you must copy the property locally, and you must free the returned PropValue by calling freeResultPropValue(), or you get a memory leak ππ«Ά
On error it returns NULL. Check SwishError() (see below) for the type of error.
- If it returns
NULLbutSwishError()is false (zero), the result just doesn't have any data for that property πΈ - If
SwishError()is true (non-zero), the property name is invalid, which means it isn't defined for the index π
When SwishError() is true, see below for how to get the specific error message. And if you want an example of using this function, check out perl/API.xs π
void freeResultPropValue(void)
This frees the PropValue you got back from getResultPropValue() π§Ή Bye bye memory π
void Free_Results_Object( SW_RESULTS results );
This frees the results object, which means it frees the whole result set ποΈ You MUST call this when you're done reading the results and before calling SwishClose() β¨
β¨ Accessing the Index Header Values β¨
Okay so every index file has header values that describe the index π These functions give you access to that data. The header data comes back as a union SWISH_HEADER_VALUE. You pass in a pointer to a SWISH_HEADER_TYPE, and the returned value tells you what type of data you got π Check out src/libtest.c and perl/API.xs for examples π
const char **SwishHeaderNames( SW_HANDLE );
This returns the list of possible header names π The list is the same for every index file of a given version of Swish-e, so you can get access to all the headers without having to list them out in your program. Main character energy π
const char **SwishIndexNames( SW_HANDLE );
This returns a list of the index files that got opened π It's literally just the list of index files you specified in the SwishInit() call. You need the name of an index file to access that index's header values π«Ά
SWISH_HEADER_VALUE SwishHeaderValue( SW_HANDLE, const char *index_name,
const char *cur_header, SWISH_HEADER_TYPE *type );
This fetches the header value for the given index file and header name π¦ The call also sets the "type" you passed in to whatever type of value got returned.
See src/libtest.c and perl/API.xs for examples π
SWISH_HEADER_VALUE SwishResultIndexValue( SW_RESULT, const char *name,
SWISH_HEADER_TYPE *type );
This one is basically SwishHeaderValue() but with a twist πΈ Instead of giving it an index file name and a swish handle, you hand it a result object, and it fetches the header value from that result's related index file π§
β¨ Accessing Property Meta Data β¨
Okay so in addition to the pre-defined standard properties, you can add your own "meta" properties π These get indexed and/or added to the list of properties returned with each result. To learn how to do this, check out the sections on the MetaNames and PropteryNames directives in the CONFIGURATION FILE π
These functions give you access to the meta data stored in an index π You can use them to figure out what meta and property info is available for an index, including all the pre-defined standard properties. See libtest.c for an example π
SWISH_META_LIST SwishMetaList( SW_HANDLE, const char *index_name );
This returns the list of meta entries for the given index file as a null-terminated array of SW_META objects π Use the functions below to pull specific fields out of the SW_META structure. Metas are distinct from properties, so don't mix them up bestie π
SWISH_META_LIST SwishPropertyList( SW_HANDLE, const char *index_name );
This is the same as SwishMetaList(), but it returns an array of properties instead of meta objects π You can extract property attributes the same way as meta objects, using the functions below.
SWISH_META_LIST SwishResultMetaList( SW_RESULT );
This is like SwishMetaList() above, but it figures out which index to use from a result object π¦
SWISH_META_LIST SwishResultPropertyList( SW_RESULT );
This is like SwishPropertyList() above, but just like SwishResultMetaList(), it uses a result object instead of an index name π«Ά
const char *SwishMetaName( SW_META );
Give this a SW_META object from one of the functions above, and it returns the meta/property's name π·οΈ You can use that name to access a property's value for a given result, like we covered above β¨
int SwishMetaType( SW_META );
This gets the data type for the given meta/property π Known types are listed in swish-e.h.
SwishMetaID( SW_META );
This gets the internal ID number for the given meta/property π’ These IDs are unique per index file, but they are not unique per results, so keep that in mind π
β¨ Checking for Errors β¨
Bestie, you should check for errors after all calls π¨ The last error is stored in the swish handle object, and it's only valid until the next operation, because each operation resets the error flags π§Ό
Some errors get flagged as "critical" errors. When that happens, you should destroy the current swish handle by calling SwishClose(). If you've got other objects in scope (like a search object or results object), destroy those first π
The types of errors that count as critical can be found in src/error.c π Right now the list includes:
- Could not open index file
- Unknown index file format
- Index file(s) is empty
- Index file error
- Invalid swish handle
- Invalid results object
int SwishError( SW_HANDLE );
This returns true if an error condition exists π© It returns the error number, which is an integer less than zero on error. Always check this before calling any of the other error functions below π«Ά
const char *SwishErrorString( SW_HANDLE );
This gives you a general text description of the current error π
const char *SwishLastErrorMsg( SW_HANDLE );
Sometimes this returns a string with specifics about the current error π For example, SwishErrorString() might return "Unknown metaname", but SwishLastErrorMsg() will return a string that includes the name of the unknown metaname π§
int SwishCriticalError( SW_HANDLE );
This returns true if the current error is a critical one π¨ On critical errors, free up any current objects and call SwishClose(), because swish may be in an unstable state π
void SwishAbortLastError( SW_HANDLE );
This is a convenience function that formats and prints the last error message, and then aborts the program π₯
void set_error_handle( FILE *where );
This sets where errors and warnings get printed (when swish is the one printing them) π¨οΈ For historical reasons, when swish-e first starts up, errors and warnings are sent to stdout π
void SwishErrorsToStderr( void );
A convenience method to send errors to stderr instead of stdout π
β¨ Utility Functions β¨
const char *SwishWordsByLetter(SWISH * sw, char *indexname, char c);
This returns all the words in the index "indexname" that begin with the letter you pass in π€ It returns NULL if the name of the index file is invalid.
Heads up bestie: this function may change in the future, since only 8-bit chars can currently be used β οΈ
char * SwsishStemWord( SW_HANDLE sw, char *in_word );
Deprecated π« Use it at your own risk, bestie.
This converts a word to its stem πΏ It only uses the original Porter Stemmer.
SW_FUZZYWORD SwishFuzzyWord( SW_RESULT r, char *word );
This stems "word" based on the fuzzy mode you selected during indexing π
Okay so the fuzzy mode used during indexing gets stored right in the index file ποΈβ¨. Every result is linked to a specific index file, so you can stem a word based on that file. Main character energy π
One possible use? Highlighting search terms in a document summary that's based on a given result ποΈπΈ. Lowkey iconic.
The methods below let you get at the data that comes back π«Ά. Bestie, the SW_FUZZYWORD object must be freed when you're done or you'll cause a memory leak π
β οΈ Forget to free theSW_FUZZYWORDobject and you get a memory leak. UseSwishFuzzyWordFree()when you're done with it.
SwishFuzzyWordList
const char **SwishFuzzyWordList( SW_FUZZYWORD fw );
This returns a null terminated list of strings from the stemmer π. Usually there's just one string, no cap π§.
Here's an example, obviously π:
SW_FYZZYWORD fuzzy_word = SwishFuzzyWord( result );
const char **word_list = SwishFuzzyWordList( fuzzy_word );
while ( *word_list )
{
printf("%s\n", *word_list );
word_list++;
}
SwishFuzzyWordFree( fuzzy_word );
If the stemmer doesn't convert the string (like when it's trying to stem numeric data), the word_list will just hold the original word π’. To check whether the stemmer actually stemmed it, look at the return value from SwishFuzzyWordError() π.
SwishFuzzyWordError
int SwishFuzzyWordError( SW_FUZZYWORD fw );
This returns zero if the stemming worked, which is the W π. Otherwise it returns a value explaining why the word wasn't stemmed. The return values are defined in the swish-e src/stemmer.h file π.
Not every stemmer sets this value correctly π¬. But SwishFuzzyWordList() always gives you a valid string no matter what this returns, so you can often just ignore it. That's what I do πββοΈ.
SwishFuzzyWordCount
int SwishFuzzyWordCount( SW_FUZZYWORD fw );
This returns how many strings are in the word list you get from SwishFuzzyWordList() π¦.
Normally it's just one, but with DoubleMetaphone it can be one or two strings π―.
SwishFuzzyMode
const char *SwishFuzzyMode( SW_RESULT r );
This returns the name of the stemmer used for the given result, which is tied to an index π.
SwishFuzzyWordFree
void SwishFuzzyWordFree( SW_FUZZYWORD fw );
This frees the memory used by the SW_FUZZYWORD π§Ή.
π Bug-Reports β¨
Bug reports go to the Swish-e discussion group π¬. Feel free to improve or enhance this feature too π.
ποΈ Author
- Original interface: Aug 2000 Jose Ruiz jmruiz@boe.es
- Updated: Aug 22, 2002 - Bill Moseley
- Interface redesigned for Swish-e version 2.3 Oct 17, 2002 - Bill Moseley
π Document Info
$Id: SWISH-LIBRARY.pod 1906 2007-02-07 19:25:16Z moseley $
Thanks for reading, bestie! This page is version 2.4.7 and was dated 2009-04-04. Stay fabulous ππ¦π
π¦ where this page comes from
- alpine 3.22: swish-e-doc 2.4.7-r17 Β· GPL-2.0-or-later
- alpine 3.23: swish-e-doc 2.4.7-r19 Β· GPL-2.0-or-later
- alpine 3.24: swish-e-doc 2.4.7-r19 Β· GPL-2.0-or-later
- debian bookworm: swish-e 2.4.7-6.1+b2
- debian trixie: swish-e 2.4.7-6.3
- ubuntu jammy: swish-e 2.4.7-6.1build1
- ubuntu noble: swish-e 2.4.7-6.2build3
- ubuntu questing: swish-e 2.4.7-7
- ubuntu resolute: swish-e 2.4.7-7.1
- ubuntu stonking: swish-e 2.4.7-7.2build1
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms