在GreenDao开源代码中添加FTS4全文检索功能

GreenDao并不支持全文检索,导致在大量数据中的查询效率低下。本文介绍了如何在GreenDao中添加支持全文检索的功能,希望对GreenDao粉有所帮助。
本文基于GreenDao V3.2.3 + rk3288 android7.1.2实测有效,读者有任何问题可留言沟通。

1.修改DaoGeneratorV3

1)Entity.java增加一个属性useFts,用来标识是否使用全文检索。

private boolean useFts;//lihuili add 20210310 for FTS 

    public boolean isUseFts() {
		return useFts;
	}

	public void setUseFts(boolean useFts) {
		this.useFts = useFts;
	}

	Entity(Schema schema, String className) {
        this.schema = schema;
        this.className = className;
        properties = new ArrayList<Property>();
        propertiesPk = new ArrayList<Property>();
        propertiesNonPk = new ArrayList<Property>();
        propertyNames = new HashSet<String>();
        indexes = new ArrayList<Index>();
        multiIndexes = new ArrayList<Index>();
        toOneRelations = new ArrayList<ToOne>();
        toManyRelations = new ArrayList<ToManyBase>();
        incomingToManyRelations = new ArrayList<ToManyBase>();
        additionalImportsEntity = new TreeSet<String>();
        additionalImportsDao = new TreeSet<String>();
        interfacesToImplement = new ArrayList<String>();
        contentProviders = new ArrayList<ContentProvider>();
        constructors = true;
        useFts = false;
    }

2)模板dao.ftl增加:如果entity.useFts为true,就创建使用FTS4的虚表

<!-- lihuili add 20210310 for FTS -->
	<#if entity.useFts>
	/** Creates the underlying database table. */
	    public static void createTable(Database db, boolean ifNotExists) {
	        String constraint = ifNotExists? "IF NOT EXISTS ": "";
	        db.execSQL("CREATE VIRTUAL TABLE " + constraint + "\"${entity.dbName}\" USING FTS4 (" + //
		<#list entity.propertiesColumns as property>
	    "\"${property.dbName}\" ${property.dbType}<#if property.constraints??> ${property.constraints} </#if><#if property_has_next>," +<#else>);");</#if> // ${property_index}: ${property.propertyName}
		</#list>
		<#if entity.indexes?has_content >
		   // Add Indexes
		<#list entity.indexes as index>
		  db.execSQL("CREATE <#if index.unique>UNIQUE </#if>INDEX " + constraint + "${index.name} ON \"${entity.dbName}\"" +
		    " (<#list index.properties 
		as property>\"${property.dbName}\"<#if (index.propertiesOrder[property_index])??> ${index.propertiesOrder[property_index]}</#if><#sep>,</#list>);");
		</#list>
		</#if>
		    }
	<#else>
		    /** Creates the underlying database table. */
		    public static void createTable(Database db, boolean ifNotExists) {
		        String constraint = ifNotExists? "IF NOT EXISTS ": "";
		        db.execSQL("CREATE TABLE " + constraint + "\"${entity.dbName}\" (" + //
		<#list entity.propertiesColumns as property>
		                "\"${property.dbName}\" ${property.dbType}<#if property.constraints??> ${property.constraints} </#if><#if property_has_next>," +<#else>);");</#if> // ${property_index}: ${property.propertyName}
		</#list>
		<#if entity.indexes?has_content >
		        // Add Indexes
		<#list entity.indexes as index>
		        db.execSQL("CREATE <#if index.unique>UNIQUE </#if>INDEX " + constraint + "${index.name} ON \"${entity.dbName}\"" +
		                " (<#list index.properties 
		as property>\"${property.dbName}\"<#if (index.propertiesOrder[property_index])??> ${index.propertiesOrder[property_index]}</#if><#sep>,</#list>);");
		</#list>
		</#if>         
		    }
	</#if> 

2.修改自动生成代码的java文件

以DaoGeneratorFaceCollectSTD.java为例:
1)创建一个15列的普通表check_list


```java
private static Entity addCheck_list(Schema schema){
    	Entity check_list = schema.addEntity("check_list");
    	check_list.addLongProperty("item_id").primaryKey().autoincrement();
    	check_list.addLongProperty("file_id");
    	check_list.addStringProperty("name");
    	check_list.addStringProperty("identy_no");
    	check_list.addStringProperty("col3");
    	check_list.addStringProperty("col4");
    	check_list.addStringProperty("col5");
    	check_list.addStringProperty("col6");
    	check_list.addStringProperty("col7");
    	check_list.addStringProperty("col8");
    	check_list.addStringProperty("col9");
    	check_list.addStringProperty("col10");
    	check_list.addStringProperty("col11");
    	check_list.addStringProperty("col12");
    	check_list.addStringProperty("col13");
    	check_list.addStringProperty("col14");
    	check_list.addStringProperty("col15");    	
    	return check_list;
    }

2)创建一个3列的虚表,这3列与普通表完全一样
关键点:需要调用setUseFts(true),明确告诉程序创建虚表。

```java
 private static Entity addCheck_list_fts(Schema schema){
    	Entity check_list_fts = schema.addEntity("check_list_fts");
    	check_list_fts.setUseFts(true);//使用FTS4
    	check_list_fts.addLongProperty("item_id").primaryKey().autoincrement();    	
    	check_list_fts.addStringProperty("name");
    	check_list_fts.addStringProperty("identy_no");    	  	
    	return check_list_fts;
}

3)在main函数中调用上面封装的函数

public static void main(String[] args) throws Exception {
        Schema schema = new Schema(SCHEMA_VERSION_INFO_DB, "com.routon.idr.facecollect.std.dao.info");
        schema.enableActiveEntitiesByDefault();
        schema.enableKeepSectionsByDefault();
        
        addCommonParam(schema);
        addFaceInfo(schema);
        addCheckfile_info(schema);
        addCheck_list(schema);
        addCheck_list_fts(schema);
        new DaoGenerator().generateAll(schema, "../iDRFaceCollectSTD/src");
    }  

4)Run As Java Application自动生成代码

3.修改DaoCoreV3

1)修改Property.java,增加支持match
注意:一定要带问号!

public class Property {
	...
	public WhereCondition match(Object value) {
		return new PropertyCondition(this, " match?", value);
	}
}

4.封装FTS查询函数

以FaceInfoCtrl.java为例:
1)函数QueryCheckListFtsByIdentyNo()调用match()构造where条件

public List<Check_list_fts> QueryCheckListFtsByIdentyNo(String identy_no){
		if(!TextUtils.isEmpty(identy_no)){
			Check_list_ftsEntityDao entityDao = new Check_list_ftsEntityDao(getDBManager());
			if(entityDao!=null){
				Check_list_ftsDao dao = entityDao.getEntityDao();
				QueryBuilder<Check_list_fts> builder = dao.queryBuilder();
				builder = builder.where(Check_list_ftsDao.Properties.Identy_no.match(identy_no));
				long beginTick = SystemClock.uptimeMillis();
				List<Check_list_fts> checkListFtss = builder.build().list();
				long endTick = SystemClock.uptimeMillis();
				Log.d(TAG, "match " + identy_no + " use " + (endTick-beginTick) + "ms");
				if(checkListFtss!=null && checkListFtss.size()>0){
					Log.d(TAG, checkListFtss.get(0).getName());
				}
				return checkListFtss;
			}
		}
		return null;
	}

5.验证测试FTS4全文检索

1)先单独运行一下添加了FTS支持的test.apk,生成一个数据库文件face_info.db, 该文件中已经自动创建了空表check_list_fts
2)创建一个插入65535条记录的sql脚本文件CHECK_LIST_FTS.sql,例:

INSERT INTO "CHECK_LIST_FTS" VALUES ('1', '夏紫寒', '642401194107180628');
INSERT INTO "CHECK_LIST_FTS" VALUES ('2', '范梦松', '220904201505271831');
INSERT INTO "CHECK_LIST_FTS" VALUES ('3', '魏孤岚', '612232196501110123');


3)从终端pull face_info.db到pc
4)在pc使用在navicat premium把CHECK_LIST_FTS.sql导入到CHECK_LIST_FTS表
5)从pc push face_info.db到终端
6)在test.apk中添加调用FTS查询的函数QueryCheckListFtsByIdentyNo()
7)对比测试普通查询和FTS4全文检索的效率
在65535条记录中,普通查询平均耗时190ms,FTS4全文检索平均耗时5ms!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值