codecamp

鸿蒙OS 融合搜索开发指导

场景介绍

索引源应用,一般为有持久化数据的应用,可以通过融合搜索接口为其应用数据建立索引,并配置全局搜索可搜索实体,帮助用户通过全局搜索应用查找本应用内的数据。应用本身也提供搜索框时,也可直接在应用内部通过融合搜索接口实现全文搜索功能。

接口说明

HarmonyOS 中的融合搜索为开发者提供以下几种能力,详见API参考。

类名 接口名 描述
SearchAbility public List<IndexData> insert(String groupId, String bundleName, List<IndexData> indexDataList) 索引插入
public List<IndexData> update(String groupId, String bundleName, List<IndexData> indexDataList) 索引更新
public List<IndexData> delete(String groupId, String bundleName, List<IndexData> indexDataList) 索引删除
SearchSession public int getSearchHitCount(String queryJsonStr) 搜索命中结果数量
public List<IndexData> search(String queryJsonStr, int start, int limit) 分页搜索
public List<Recommendation> groupSearch(String queryJsonStr, int groupLimit) 分组搜索

开发步骤

实例化 SearchAbility,连接融合搜索服务。

SearchAbility searchAbility = new SearchAbility(context);
CountDownLatch lock = new CountDownLatch(1);
// 连接服务
searchAbility.connect(new ServiceConnectCallback() {
    @Override
    public void onConnect() {
        lock.countDown();
    }

        
    @Override
    public void onDisconnect() {
    }
});
// 等待回调,最长等待时间可自定义
lock.await(3000, TimeUnit.MILLISECONDS);
// 连接失败可重试

设置索引属性。

// 构造索引属性
List<IndexForm> indexFormList = new ArrayList<>();
IndexForm primaryKey = new IndexForm("id", IndexType.NO_ANALYZED, true, true, false); // 主键,不分词
indexFormList.add(primaryKey);
IndexForm title = new IndexForm("title", IndexType.ANALYZED, false, true, true); // 分词
indexFormList.add(title);
IndexForm tagType = new IndexForm("tag_type", IndexType.SORTED, false, true, false); // 分词,同时支持排序、分组
indexFormList.add(tagType);
IndexForm ocrText = new IndexForm("ocr_text", IndexType.SORTED_NO_ANALYZED, false, true, false); // 支持排序、分组,不分词,所以也支持范围搜索
indexFormList.add(ocrText);
IndexForm dateTaken = new IndexForm("datetaken", IndexType.LONG, false, true, false); // 支持排序和范围查询
indexFormList.add(dateTaken);
IndexForm bucketId = new IndexForm("bucket_id", IndexType.INTEGER, false, true, false); // 支持排序和范围查询
indexFormList.add(bucketId);
IndexForm latitude = new IndexForm("latitude", IndexType.FLOAT, false, true, false); // 支持范围搜索
indexFormList.add(latitude);
IndexForm longitude = new IndexForm("longitude", IndexType.DOUBLE, false, true, false); // 支持范围搜索
indexFormList.add(longitude);

 
// 设置索引属性
int result = searchAbility.setIndexForm(bundleName, 1, indexFormList);
// 设置失败可重试

插入索引。

// 构建索引数据List<IndexData> indexDataList = new ArrayList<>();for (int i = 0; i < 5; i++) {    IndexData indexData = new IndexData();    indexData.put("id", "id" + i);    indexData.put("title", "title" + i);    indexData.put("tag_type", "tag_type" + i);    indexData.put("ocr_text", "ocr_text" + i);    indexData.put("dat// 构建索引数据
List<IndexData> indexDataList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    IndexData indexData = new IndexData();
    indexData.put("id", "id" + i);
    indexData.put("title", "title" + i);
    indexData.put("tag_type", "tag_type" + i);
    indexData.put("ocr_text", "ocr_text" + i);
    indexData.put("datetaken", System.currentTimeMillis());
    indexData.put("bucket_id", i);
    indexData.put("latitude", i / 5.0 * 180);
    indexData.put("longitude", i / 5.0 * 360);
    indexDataList.add(indexData);
}
// 插入索引
List<IndexData> failedList = searchAbility.insert(SearchParameter.DEFAULT_GROUP, bundleName, indexDataList);
// 失败的记录可以持久化,稍后重试etaken", System.currentTimeMillis());    indexData.put("bucket_id", i);    indexData.put("latitude", i / 5.0 * 180);    indexData.put("longitude", i / 5.0 * 360);    indexDataList.add(indexData);}// 插入索引List<IndexData> failedList = searchAbility.insert(SearchParameter.DEFAULT_GROUP, bundleName, indexDataList);// 失败的记录可以持久化,稍后重试

构建查询。

// 构建查询
JSONObject jsonObject = new JSONObject();

    
// SearchParameter.QUERY对应用户输入,搜索域应该都是分词的
// 这里假设用户输入是“天空”,要在"title", "tag_type"这两个域上发起搜索
JSONObject query = new JSONObject();
query.put("天空", new JSONArray(Arrays.asList("title", "tag_type")));
jsonObject.put(SearchParameter.QUERY, query);

 
// SearchParameter.FILTER_CONDITION对应的JSONArray里可以添加搜索条件
// 对于索引库里的一条索引,JSONArray下的每个JSONObject指定的条件都必须满足才会命中,JSONObject里的条件组合满足其中一个,这个JSONObject指定的条件即可满足
JSONArray filterCondition = new JSONArray();
// 第一个条件,一个域上可能取多个值
JSONObject filter1 = new JSONObject();
filter1.put("bucket_id", new JSONArray(Arrays.asList(0, 1, 2))); // 一条索引在"bucket_id"的取值为0或1或2就能命中
filter1.put("id", new JSONArray(Arrays.asList(0, 1))); // 或者在"id"的取值为0或者1也可以命中
filterCondition.put(filter1);
// 第二个条件,一个值可能在多个域上命中
JSONObject filter2 = new JSONObject();
filter2.put("tag_type", new JSONArray(Arrays.asList("白云")));
filter2.put("ocr_text", new JSONArray(Arrays.asList("白云"))); // 一条索引只要在"tag_type"或者"ocr_text"上命中"白云"就能命中
filterCondition.put(filter2);
jsonObject.put(SearchParameter.FILTER_CONDITION, filterCondition); // 一条索引要同时满足第一和第二个条件才能命中

 
// SearchParameter.DEVICE_ID_LIST对应设备ID,匹配指定设备ID的索引才会命中
JSONObject deviceId = new JSONObject();
deviceId.put("device_id", new JSONArray(Arrays.asList("localDeviceId")));
jsonObject.put(SearchParameter.DEVICE_ID_LIST, deviceId);

 
// 可以在支持范围搜索的索引域上发起范围搜索,一条索引在指定域的值都落在对应的指定范围才会命中
JSONObject latitude = new JSONObject();
latitude.put(SearchParameter.LOWER, -40.0f); // inclusive
latitude.put(SearchParameter.UPPER, 40.0.f); // inclusive
jsonObject.put("latitude", latitude); // 纬度必须在[-40.0f, 40.0f]
JSONObject longitude new JSONObject();
longitude.put(SearchParameter.LOWER, -90.0); // inclusive
longitude.put(SearchParameter.UPPER, 90.0);  // inclusive
jsonObject.put("longitude", longitude); // 经度必须在[-90.0, 90.0]

 
// SearchParameter.ORDER_BY对应搜索结果的排序,排序字段通过SearchParameter.ASC和SearchParameter.DESC
// 指定搜索结果在这个字段上按照升序、降序排序,这里填充字段的顺序是重要的,比如这里两个索引之间会先在"id"
// 字段上升序排序,只有在"id"上相同时,才会继续在"datetaken"上降序排序,以此类推
JSONObject order = new JSONObject();
order.put("id", SearchParameter.ASC);
order.put("title", SearchParameter.ASC);
order.put("datetaken", SearchParameter.DESC);
jsonObject.put(SearchParameter.ORDER_BY, order);

 
// SearchParameter.GROUP_FIELD_LIST对应的群组搜索的域,调用gruopSearch接口需要指定
jsonObject.put(SearchParameter.GROUP_FIELD_LIST, new JSONArray(Arrays.asList("tag_type", "ocr_text")));

 
// 得到查询字符串
String queryJsonStr = jsonObject.toString();
// 构建的json字符串如下:
/**
{
    "SearchParameter.QUERY": {
        "天空": [
            "title",
            "tag_type"
        ]
    },
    "SearchParameter.FILTER_CONDITION": [
        {
            "bucket_id": [
                0,
                1,
                2
            ],
            "id": [
                0,
                1
            ]
        },
        {
            "tag_type": [
                "白云"
            ],
            "ocr_text": [
                "白云"
            ]
        }
    ],
    "SearchParameter.DEVICE_ID_LIST": {
        "device_id": [
            "localDeviceId"
        ]
    },
    "latitude": {
        "SearchParameter.LOWER": -40.0,
        "SearchParameter.UPPER": 40.0
    },
    "longitude": {
        "SearchParameter.LOWER": -90.0,
        "SearchParameter.UPPER": 90.0
    },
    "SearchParameter.ORDER_BY": {
        "id": "ASC",
        "title": "ASC",
        "datetaken": "DESC"
    },
    "SearchParameter.GROUP_FIELD_LIST": [
        "tag_type",
        "ocr_text"
    ]
}
**/

开始搜索会话,发起搜索。

// 开始搜索会话
SearchSession searchSession = searchAbility.beginSearch(SearchParameter.DEFAULT_GROUP, bundleName);
if (searchSession == null) {
    return;
}
try {
    int hit = searchSession.getSearchHitCount(queryJsonStr); // 获取总命中数
    int batch = 50; // 每页最多返回50个结果
    for (int i = 0; i < hit; i += batch) {
        List<IndexData> result = searchSession.search(queryJsonStr, i, batch);
        ...
        // 处理IndexData
    }
    int groupLimit = 10; // 每个分组域上最多返回10个分组结果
    List<Recommendation> result = searchSession.groupSearch(queryJsonStr, groupLimit);
    // 处理Recommendation
    for (Recommendation recommendation : result) {
        HiLog.info(LABEL, "field: %{public}s, value: %{public}s, count: %{public}d", recommedation.getField(), recommendation.getValue(), recommendation.getCount());
    }
} finally {
    // 释放资源
    searchAbility.endSearch(SearchParameter.DEFAULT_GROUP, bundleName, searchSession);
}
鸿蒙OS 融合搜索概述
鸿蒙OS 数据存储管理概述
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

鸿蒙OS 开发

鸿蒙OS 术语

鸿蒙OS Java API参考

鸿蒙OS ohos.aafwk.ability

鸿蒙OS ohos.aafwk.abilityjet.activedata

鸿蒙OS ohos.aafwk.content

鸿蒙OS java.lang

鸿蒙OS java.Util

鸿蒙OS java.Util class

鸿蒙OS ohos.data.dataability

鸿蒙OS ohos.data.dataability class

鸿蒙OS ohos.agp.components

鸿蒙OS ohos.agp.components interface

鸿蒙OS ohos.agp.components class

鸿蒙OS ohos.global.configuration

鸿蒙OS java.io

鸿蒙OS ohos.data.resultset

鸿蒙OS ohos.data.resultset interface

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }