树叶云鸿蒙OS教程:鸿蒙OS 融合搜索开发指导

场景介绍

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

接口说明

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

类名接口名描述
SearchAbilitypublic 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)索引删除
SearchSessionpublic 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);
}

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/203925.html<

(0)
运维的头像运维
上一篇2025-04-06 22:14
下一篇 2025-04-06 22:15

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注