Open topic with navigation

TIBCO® Patterns 6.1.2

# A Simple Example

Here is a listing of source file `lgrep.c`, `a` simple, fully functional program that loads a text file of one-field records into the DevKit, then looks up records for a query. If you are familiar with Unix systems, consider it as an TIBCO Patterns analogue of the grep utility. While simple, this program demonstrates most of the DevKit's essential functions.

DevKit type names and function names appear in boldface. DevKit functions fall into three categories:

| • | Command functions perform administrative tasks, as well as matching and machine learning scoring operations. These are the functions that do real work. `lgrep.c` invokes two command functions: `lkt_dbload` to load data, and `lkt_dbsearch` to search the data.

| • | Parameter functions create, manipulate, and destroy the input and output parameters that are passed to and from command functions. Most of the functions shown in boldface are parameter functions (for example, `lpar_create_lst,` l`par_create_record`, `lpar_create_int`, `lpar_destroy`).

| • | System functions perform DevKit system tasks. The most important are for startup (`lkt_devkit_init`) and shutdown (`lkt_devkit_shutdown`).

In outline, `lgrep.c` performs the following steps:

| 1. | DevKit system initialization.

| 2. | Read the data file,

Packaging each line as a DevKit record object and

Appending it to a DevKit list object.

| 3. | Define the field structure for the table.

| 4. | Call the `lkt_dbload` command function with the list of records and a string that names the new database. The `lkt_dbload` command creates and populates the database.

| 5. | Build a list of search parameters (srchpars).

| 6. | Call the function `lkt_dbsearch` with the query, the database name, and the list of search parameters. `lkt_dbsearch` returns a ranked list of record objects (matches).

| 7. | Print some statistics, including the search time, followed by the text of each record in the ranked list.

| 8. | Call the system shutdown function `lkt_devkit_shutdown`.

## lgrep.c

    #include <stdio.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "netrics/devkit.h"
    #define TRUE                1
    #define FALSE               0
    typedef unsigned char       UCHAR;
    #define MAX_RECORD_LEN      2048
    char    *ProgName;
    static void     checkerr( dvkerr_t err, char *function );
    int main( int argc, char *argv[] )
    {
        int qlen, matchesret, matchnum, numrecs, reclen ;
        char *query, *datafile, dataline[MAX_RECORD_LEN], reckey[10];
        FILE *fp;
        int fldlens[1];
        /* our database will have one field named "text" */
        static const UCHAR *fldnames[1] = { "text" };
        const UCHAR    *rectxt;
        /* Simple lpars */
    lpar_t      dbname, qpar, lpar;
        /* Record lpars */
    lpar_t      record;
        /* List lpars */
    lpar_t      dbpars, reclist, names, srchpars, stats, matches, minfo;
    dvkerr_t    err;
        ProgName = argv[0];
        if (argc != 3) {
                fprintf(stderr, "Usage: %s <query> <datafile>\n", ProgName);
                exit(-1);
        }
        /* 1. INITIALIZE THE DEVKIT */
        err = lkt_devkit_init();
        checkerr(err, "lkt_devkit_init");
        query = argv[1];
        qlen  = strlen(query);
        datafile = argv[2];
        if (!(fp = fopen(datafile, "r"))) {
                fprintf(stderr, "%s: Can't open file `%s'\n", ProgName,
                        datafile);
                exit(-1);
        }
        /* 2. READ THE DATA FILE */
        numrecs = 0;
        reclist = lpar_create_lst(LPAR_LST_GENERIC);
        while (fgets(dataline, MAX_RECORD_LEN, fp)) {
                /* 2A: CREATE A RECORD WITH `dataline' AS SEARCHABLE TEXT */
                record = lpar_create_record();
                sprintf(reckey, "%06d", ++numrecs);
    lpar_set_record_key(record, (UCHAR *)reckey);
                fldlens[0] = strlen(dataline);
                if (dataline[fldlens[0]-1] == '\n') {  /* Chop newline */
                        fldlens[0]--;
                }
                rectxt = (UCHAR *)dataline;
    lpar_set_record_srchtxt(record, rectxt, fldlens[0]);
                /* Record field structure must match database field structure */
    lpar_set_record_srchflds(record, fldlens, 1);
                /* 2B: ADD RECORD TO THE RECORD LIST */
    lpar_append_lst(reclist, record);
        }
        fclose(fp);
        /* Package file name as the name for the database */
        dbname  = lpar_create_str(LPAR_STR_DBDESCRIPTOR, (UCHAR *)datafile);
        /* 3. DEFINE THE FIELDS */
        dbpars = lpar_create_lst(LPAR_LST_GENERIC);
        lpar = lpar_create_strarr(LPAR_STRARR_FIELDNAMES, fldnames, 1);
    lpar_append_lst(dbpars, lpar);
        /* 4. LOAD THE DATABASE */
        err = lkt_dbload(LPAR_NULL, dbname, dbpars, reclist, &stats);
        checkerr(err, "lkt_dbload");
        /* Clean up */
    lpar_destroy(reclist);
    lpar_destroy(stats);
    lpar_destroy(dbpars);
        /* 5. SET UP INPUT PARAMETERS FOR LOOKUP */
        srchpars = lpar_create_lst(LPAR_LST_GENERIC);
        lpar = lpar_create_int(LPAR_INT_MATCHESREQ, 10);
    lpar_append_lst(srchpars, lpar);
        /* Add name to a list of names, and package query */
        names = lpar_create_lst(LPAR_LST_GENERIC);
    lpar_append_lst(names, dbname);
        qpar = lpar_create_blk(LPAR_BLK_SEARCHQUERY, (UCHAR *)query, qlen);
        /* 6. DO THE LOOKUP */
        err = lkt_dbsearch(LPAR_NULL, names, LPAR_NULL, qpar, srchpars, &stats,
                           &matches, &minfo);
        checkerr(err, "lkt_dbsearch");
        /* 7. PRINT THE RESULTS */
        printf("Query: `%s'\n", query);
        matchesret = lpar_get_lst_num_items(matches);
        printf("Matches returned: %d\n", matchesret);
        lpar = lpar_find_lst_lpar(stats, LPAR_DBL_SEARCHTIME);
        printf("Lookup time: %.2f seconds\n", lpar_get_dbl(lpar));
        printf("\n");
        /* Print the ranked list of records */
        for (matchnum=0 ; matchnum < matchesret ; matchnum++) {
                record = lpar_get_lst_item(matches, matchnum);
                rectxt = lpar_get_record_srchtxt(record, &reclen);
                printf("[%d] `%.*s'\n", matchnum+1, reclen, rectxt);
        }
        /* Clean up */
    lpar_destroy(names);
    lpar_destroy(qpar);
    lpar_destroy(srchpars);
    lpar_destroy(stats);
    lpar_destroy(matches);
    lpar_destroy(minfo);
        /* 8. SYSTEM TERMINATION */
        err = lkt_devkit_shutdown();
        checkerr(err, "lkt_devkit_shutdown");
        exit(0);
    }
    static void
    checkerr( dvkerr_t err, char *function )
    {
    lpar_t  erritem;
        if (DVKERR(err)) {
                fprintf(stderr, "%s() returned %d (%s)\n", function,
    DVKERR(err), dvkerr_get_string(err));
                if ((erritem = dvkerr_get_item(err))) {
    lpar_fprintf(stderr, erritem, -1);
                }
    dvkerr_clear(err);
                exit(-1);
        }
    }

On a Unix system, after compiling `lgrep.c` and linking it with the DevKit, run the program as follows:

    lgrep dictioneryprblembounds cspapers.lst

where `dictioneryprblembounds` is an inexact search query, and `cspapers.lst` is a text file of single-line records. The output looks like this, where some long lines are abbreviated:

    Query: 'dictioneryprblembounds'
    Matches returned: 10
    Lookup time: 0.01 seconds
    [1] `Andersson, Optimal Bounds on the Dictionary Problem|LNCS|401|1989'
    [2] `..., Upper and Lower Bounds for the Dictionary Problem|LNCS|318|1988'
    [3] `Sundar, A Lower Bound for the Dictionary Problem ...|FOCS|32|1991'
    [4] `... Concurrency Methods for the Dictionary Problem: A Survey|...'
    [5] `Fich, Lower Bounds for the Cycle Detection Problem|STOC||1981'
    [6] `Fich, Lower Bounds for the Cycle Detection Problem|JCSS|26|1983'
    [7] `... Bounds for Communication Complexity Problems|ACTAINF|28|1991'
    [8] `... Dictionary-Matching on Unbounded Alphabets ...|LIBTR||1993'
    [9] `... Dictionary-Matching on Unbounded Alphabets...|ALGORITHMS|18|1995'
    [10] `Willard, Lower Bounds for Dynamic Range Query Problems ...|ICALP||1986'

The`lgrep` program loads data from a file to service a single query. Most DevKit applications run as services that maintain searchable data in memory, concurrently processing matching or machine learning scoring requests and database administration requests. In either case, the steps in assembling and passing parameters for the `lkt_dbload` and `lkt_dbsearch` functions are the same.

That is how simple it is to use DevKit.

Did you find this helpful?

Yes No
Great!
Thanks for taking the time to give us some feedback.
Sorry about that

Why wasn't this helpful? (check all that apply)

Could not find what I was looking for
Instructions confusing or unclear
Instructions did not work

Want to tell us more?

Please select at least one option or provide details about the issue!!

Error occurred while submitting feedback.

Error2 occurred while submitting feedback.

TIBCO® Patterns

Copyright © 2010-2025. Cloud Software Group, Inc. All Rights Reserved.