标题：精准搜索
全文精准搜索
JZSearch全文精准搜索中间件内核经过精心设计，具有高扩展性和高通用性。可支持文本、数字、日期、字符串等各种数据类型的高效索引，支持丰富的查询语言和查询类型，支持少数民族语言的搜索。
同时，全文搜索中间件可以无缝地与现有数据库系统融合，实现全文搜索与相关的数据库管理应用系统。
其主要特色在于：
* 可以按照任意指定字段的排序，支持指定字段的搜索，也可以搜索多个字段，以及复杂表达式的综合搜索； 
* 支持精确匹配以及模糊匹配，默认为精确匹配，忽略字母大小写进行模糊匹配； 
* 实现的是多线程搜索服务； 
* 每秒可索引3000条记录（主要瓶颈为数据库或文件记录的读取效率）；搜索速度在毫秒级别。 
* 兼容当前所有厂商的数据库系统，其中SQL Server, Oracle, MySQL，DB2等。建立索引接口（1）索引初始化操作
/*********************************************************************
*
* Func Name : LJIndexer_Init
*
* Description: 索引系统初始化，必须初始化后，才能使用CLJIndexer
*
* Parameters : sDictFilename：词典文件名；为空时，采用n-gram索引方法
* sFieldInfoFile:域字段信息，用于支持多域索引，为空则只支持一个字段
* 如果API定义了CODE_LIMIT，需要从开发商处获得授权码，作为第三个参数
* Returns : success or fail
* Author : 灵玖软件
* History : 
*********************************************************************/
#ifndef CODE_LIMIT
LJSEARCHAPI_API bool LJIndexer_Init(const char *sDictFilename=0,const char *sFieldInfoFile=0);
#else
LJSEARCHAPI_API bool LJIndexer_Init(const char *sDictFilename=0,const char *sFieldInfoFile=0,const char *sLicenseCodes=0);
#endif
（2）多字段定义操作
/*********************************************************************
* 系统定义的字段数据类型
* 
*********************************************************************/
#define FIELD_TYPE_TEXT 1 //文本类型
#define FIELD_TYPE_INT 2 //整型数
#define FIELD_TYPE_LONG 3 //长整型数
#define FIELD_TYPE_DATETIME 4 //日期类型
/*********************************************************************
*
* Func Name : LJIndexer_FieldAdd
*
* Description: 添加字段信息
*
* Parameters : sFieldName:域名称，在索引建立与搜索过程中，域的唯一标示符
* sDBFieldName：对应于数据库的字段名称；在数据库搜索的时候，用于获取数据库的数据
* nFieldType:数据类型，对应的范围如下：
* //FIELD_TYPE_TEXT
* //FIELD_TYPE_INT
* //FIELD_TYPE_LONG
* //FIELD_TYPE_DATETIME
* bIndexed:是否需要索引
* bRetrieved:搜索结果中是否要输出该字段内容
* bGeneral:是否纳入通配搜索的范畴
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
LJSEARCHAPI_API bool LJIndexer_FieldAdd(const char *sFieldName,const char *sDBFieldName,int nFieldType,bool bIndexed,bool bRetrieved,bool bGeneral=false);
/*********************************************************************
*
* Func Name : LJIndexer_FieldSave
*
* Description: 保存字段定义的内容，一般都在定义完LJIndexer_FieldAdd之后，执行
*
* Parameters : sFieldInfoDataFile:保存的域信息数据文件
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
LJSEARCHAPI_API bool LJIndexer_FieldSave(const char *sFieldInfoDataFile);
/*********************************************************************
*
* Func Name : LJIndexer_FieldLoad
*
* Description: 读取已经保存好的域信息数据文件
*
* Parameters : sFieldInfoDataFile:保存的域信息数据文件
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
LJSEARCHAPI_API bool LJIndexer_FieldLoad(const char *sFieldInfoDataFile);
（3）索引系统退出
/*********************************************************************
*
* Func Name : LJIndexer_Exit
*
* Description: 索引系统退出，索引相关的内存全部释放
*
* Parameters : 
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
LJSEARCHAPI_API bool LJIndexer_Exit();
（4）索引合并操作
/*********************************************************************
*
* Func Name : LJIndexer_Merge
*
* Description: 索引合并，要求sIndexFile1的doc_id编号均小于sIndexFile2的doc_id
*
* Parameters : sIndexFile1：索引文件1
* sIndexFile2：索引文件2
* sIndexMerged：索引合并后的文件名
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
LJSEARCHAPI_API bool LJIndexer_Merge(const char *sIndexFile1,const char *sIndexFile2,const char *sIndexMerged);
（5）索引类操作
/*********************************************************************
*
* Func Name : CLJIndexer
*
* Description: 建立索引的类
*
* Parameters : 
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
//
class LJSEARCHAPI_API CLJIndexer {
public:
CLJIndexer(int nMaxMemSize=512000000);
//内存大小控制
~CLJIndexer(void);
// TODO: add your methods here.
int MemIndexing(const char *pText,int doc_id,const char *sFieldName=0,int nMemSize=0);
//索引一段内存；
//pText:待索引的内存块指针
//doc_id由应用程序维护，
//sFieldName：字段名称，为空则表示无字段信息，则该索引不支持多字段索引与检索
//nMemSize:指的是pText内存块的大小，默认为0，需要系统通过strlen自行计算内存大小
int FileIndexing(const char *sTextFilename,int doc_id,const char *sFieldName=0);
//索引一个文本文件
//sTextFilename:文本文件名
//doc_id由应用程序维护
//sFieldName：字段名称，为空则表示无字段信息
int IdIndexing(int term_id,int doc_id,const char *sFieldName=0);
//词ID索引
//term_id:词ID
//doc_id由应用程序维护
//sFieldName：字段名称，为空则表示无字段信息
bool Save(const char *sIndexFile);
//索引保存的名称
//一般都选择在索引建立全部完成后，调用。
private://以下部分为系统使用，应用开发者不要改写，只能读取数据
int m_nHandle;//索引器的Handle，无需调用申请
};全文检索接口（1）搜索的排序选项
/*********************************************************************
* 搜索的排序选项
* 
*********************************************************************/
#define SORT_TYPE_DOCID 1//按照Doc ID排序，默认方式
#define SORT_TYPE_RELEVANCE 2//按照相关度排序
（2）搜索的初始化设置
/*********************************************************************
*
* Func Name : LJSearch_Init
*
* Description: 搜索系统初始化，必须初始化后，才能使用CLJSearch
*
* Parameters :sIndexFile：已经建立的索引文件 
* sDictFilename：词典文件名；为空时，采用n-gram索引方法
* sFieldInfoFile:域字段信息，用于支持多域索引，为空则只支持一个字段
* 如果API定义了CODE_LIMIT，需要从开发商处获得授权码，作为第三个参数
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
#ifndef CODE_LIMIT
LJSEARCHAPI_API bool LJSearch_Init(const char *sIndexFile,const char *sDictFilename=0,const char *sFieldInfoFile=0);
#else
LJSEARCHAPI_API bool LJSearch_Init(const char *sIndexFile,const char *sDictFilename=0,const char *sFieldInfoFile=0,const char *sLicenseCodes=0);
#endif
（3）搜索系统的退出
/*********************************************************************
*
* Func Name : LJSearch_Exit
*
* Description: 搜索系统退出，释放所有相关的内存
*
* Parameters :
* Returns : success or fail
* Author : 灵玖软件 
* History : 
*********************************************************************/
LJSEARCHAPI_API bool LJSearch_Exit();
//系统退出
（4）搜索结果的内存存储格式
/*********************************************************************
*
* Data Structure Name : tRESULT_RECORD
*
* Description: 搜索结果结构，用于检索计算使用
*
* Parameters :
* Returns : 
* Author : 灵玖软件 
* History : 
*********************************************************************/
typedef struct tRESULT_RECORD {//搜索结果结构，用于检索计算使用
int doc_id;
int offset;//在域字段内的偏移量
double score;//排序用的打分
}RESULT_RECORD;
typedef RESULT_RECORD * RESULT_RECORD_VECTOR;
（5）搜索类
/*********************************************************************
*
* Class Name : CLJSearcher
*
* Description: 用于搜索的类
*
* Parameters : 
* Returns : 
* Author : 灵玖软件 
* History : 
*********************************************************************/
//
class LJSEARCHAPI_API CLJSearcher{
public:
CLJSearcher(int sort_type=SORT_TYPE_DOCID);
~CLJSearcher(void);
// TODO: add your methods here.
void Search(const char *query_line,int nStart,int nPageCount,const char *sResultName);
//query_line: 查询表达式
//nStart:记录起始地址
//nPageCount：当前页返回结果数目
//nPageCount=-1:当前页需要返回所有的结果数目
//sResultName：结果存储的XML地址
const RESULT_RECORD_VECTOR CLJSearcher::Search(const char *query_line,int *p_nResultCountRet);
//query_line: 查询表达式
//p_nResultCountRet:搜索结果总数
private://以下部分为系统使用，应用开发者不要改写，只能读取数据
int m_nHandle;
int m_nSortType;//排序方法编号
};检索语法说明/*********************************************************************
*
* 查询表达式语法说明
*
*********************************************************************/
/*********************************************************************
{[FIELD] fieldname [AND/OR/NOT/NEAR/PREC] value1 value2 ... value_n}+
说明：
1.查询是由 [FIELD] fieldname [AND/OR/NOT/NEAR/PREC] value1 value2 ... value_n 形式的表达式无限叠加组成的；可以针对多个字段进行查询，也可以针对同一个字段编写多条查询语句；
2.其中每个字符串之间采用空格或者TAB键隔开；
3.其中[FIELD]指定字段名称；
4.[AND/OR/NOT/NEAR/PREC]为候选的操作符；操作符的意义解释如下：
1) AND: 与操作，即返回的结果必须同时包括后面指定的值value1 value2 ... value_n；
2) OR： 或操作，即返回的结果必须包括后面指定值范围value1 value2 ... value_n中的任意一个；
3)NOT: 非操作，即返回的结果不能包括后面指定值范围value1 value2 ... value_n中的任意一个；
4)NEAR: 邻接操作：即返回的结果中，后续的搜索串value1 value2 ... value_n必须出现在邻接的位置上（系统目前自定义为10个词间隔）
5)PREC: 精准操作：即返回的结果中，如果包含数据的话，必须严格匹配:例如检索号码“GB 997”，不能命中“GB 1997-2009”，或者"GB 9970"，只能是“GB 997”或者"GB 997-2008"。
5.fieldname为索引字段名称，必须和实现建立索引对应的字段名一致；
也可以给出通配符 *，表示在指定的通配符字段范围内任意搜索；
6.检索语法示例：
//Sample1: [FIELD] title [AND] 解放军 
//Sample2: [FIELD] title [AND] 甲流 
//Sample3: [FIELD] title [AND] 解放军 甲流 
//Sample4: [FIELD] title [OR] 解放军 甲流
//Sample5: [FIELD] title [AND] 解放军 [FIELD] title [NOT] 甲流
//Sample6: "[FIELD] content [AND] 解放军 张雁灵 [FIELD] title [AND] 解放军
//Sample7: "[FIELD] content [AND] 解放军 张雁灵 [FIELD] title [AND] 解放军
//Sample8: [FIELD] title [AND] 解放军某部发生数百人感染甲流疫情
//Sample9: [FIELD] title [AND] 解放军某部发生数百人感染甲流疫情
//Sample10: [FIELD] content [AND] 甲型H1N1流感
//Sample11: [FIELD] content [NEAR] 张雁灵 解放军
//Sample12: [FIELD] content [AND] 解放军 [FIELD] content [NOT] 张雁灵
*********************************************************************/建立索引的示例程序//////////////////////////////////////////////////////////////////////////
//
// 以下部分为索引建立的API调用示例
//
//////////////////////////////////////////////////////////////////////////
//索引初始化
LJIndexer_Init("E:/LJSearch20/Data/dictionary.pdat",NULL,"LingjoinICTCLAS2010*~!@#$%&&%$#@!~*");
//设置字段信息
LJIndexer_FieldAdd("title",NULL,FIELD_TYPE_TEXT,true,true,true);
//对标题建索引，需要搜索
LJIndexer_FieldAdd("content",NULL,FIELD_TYPE_TEXT,true,true,true);
//对内容建索引，需要搜索
LJIndexer_FieldSave("FieldInfo.dat");
//保存字段信息
CLJIndexer *pIndexer=new CLJIndexer();
//对文档列表进行索引
for (int doc_id=0;doc_id<vecFileList.size();doc_id++)
{//索引一个文件，注意：vecFileList存储的是文件名向量
pIndexer->MemIndexing(vecFileList[doc_id].c_str(),doc_id,"title");
//对文件标题进行索引
printf("Indexing %s title completed!\n",vecFileList[doc_id].c_str());
pIndexer->FileIndexing(vecFileList[doc_id].c_str(),doc_id,"content");
//对文件内容进行索引
printf("Indexing %s content completed!\n",vecFileList[doc_id].c_str());
}
pIndexer->Save("Test0430test");//保存索引结果
delete pIndexer;//索引完成，释放空间
LJIndexer_Exit();//退出索引系统
搜索系统的示例程序
LJSearch_Init("Test0430test","E:/LJSearch20/Data/dictionary.pdat","FieldInfo.dat","LingjoinICTCLAS2010*~!@#$%&&%$#@!~*");
//搜索系统初始化
CLJSearcher *pSearcher=new CLJSearcher(SORT_TYPE_RELEVANCE);//按照相关度排序
//申请搜索类
int nRecordCount=0;
RESULT_RECORD_VECTOR pResult =0;
int nLen;
char *pQueryString,*sLine;
sLine=new char[100];
strcpy(sLine,"[FIELD] content [AND] 解放军 张雁灵");//甲型H1N1流感
//Sample1: [FIELD] title [AND] 解放军 
//Sample2: [FIELD] title [AND] 甲流 
//Sample3: [FIELD] title [AND] 解放军 甲流 
//Sample4: [FIELD] title [OR] 解放军 甲流
//Sample5: [FIELD] title [AND] 解放军 [FIELD] title [NOT] 甲流
//Sample6: "[FIELD] content [AND] 解放军 张雁灵 [FIELD] title [AND] 解放军"
//Sample7: "[FIELD] content [AND] 解放军 张雁灵 [FIELD] title [AND] 解放军"
//Sample8: [FIELD] title [AND] 解放军某部发生数百人感染甲流疫情
//Sample9: [FIELD] title [AND] 解放军某部发生数百人感染甲流疫情
//Sample10: [FIELD] content [AND] 甲型H1N1流感
//Sample11: [FIELD] content [NEAR] 张雁灵 解放军
//Sample12: [FIELD] content [AND] 解放军 [FIELD] content [NOT] 张雁灵
int nSize=0;
pQueryString=sLine;
pResult=pSearcher->Search(pQueryString,&nRecordCount);
//搜索pQuerySearch，结果总数存在nRecordCount内，搜索结果数组指针存储在pResult
printf("Query=%s, Search Result Count=%d, list as follows:\n",pQueryString,nRecordCount);
//逐个输出搜索结果
for (int i=0;i<nRecordCount;i++)
{
printf("No.%d:doc_id=%d===%s[%d] score=%f\n",
i,
pResult[i].doc_id,
vecFileList[pResult[i].doc_id].c_str(),
pResult[i].offset,
pResult[i].score
);
} 
delete pSearcher;//释放搜索类
delete sLine;
LJSearch_Exit();//退出搜索系统