融合搜索:开发指导

本文介绍了如何在HarmonyOS中利用融合搜索接口为应用建立索引,实现全局搜索和应用内部全文搜索功能。内容包括场景介绍、接口说明及详细的开发步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

场景介绍

接口说明

开发步骤


场景介绍

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

接口说明

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

表1 融合搜索接口功能介绍

类名

接口名

描述

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)

分组搜索

开发步骤

  1. 实例化SearchAbility,连接融合搜索服务。
    SearchAbility searchAbility = new SearchAbility(context);
    String bundleName = context.getBundleName();
    CountDownLatch lock = new CountDownLatch(1);
     
    // 连接服务
    searchAbility.connect(new ServiceConnectCallback() {
        @Override
        public void onConnect() {
            lock.countDown();
        }
     
        @Override
        public void onDisconnect() {
        }
    });
     
    // 等待回调,最长等待时间可自定义。
    try {
        lock.await(3000, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        HiLog.error(LABEL, "await failed, %{public}s", e.getMessage());
    }
    // 连接失败可重试。
    

     

  2. 设置索引属性。
    // 构造索引属性
    List<IndexForm> indexFormList = new ArrayList<IndexForm>() { {
        add(new IndexForm("id", IndexType.NO_ANALYZED, true, true, false)); // 主键,不分词
        add(new IndexForm("title", IndexType.ANALYZED, false, true, true)); // 分词
        add(new IndexForm("tag", IndexType.SORTED, false, true, false)); // 分词,同时支持排序、分组
        add(new IndexForm("ocr_text", IndexType.SORTED_NO_ANALYZED, false, true, false)); // 支持排序、分组,不分词,所以也支持范围搜索
        add(new IndexForm("datetaken", IndexType.LONG, false, true, false)); // 支持排序和范围查询
        add(new IndexForm("bucket_id", IndexType.INTEGER, false, true, false)); // 支持排序和范围查询
        add(new IndexForm("latitude", IndexType.FLOAT, false, true, false)); // 支持范围搜索
        add(new IndexForm("longitude", IndexType.DOUBLE, false, true, false)); // 支持范围搜索
    } };
     
    // 设置索引属性
    int result = searchAbility.setIndexForm(bundleName, 1, indexFormList);
    // 设置失败可重试

     

  3. 插入索引。
    // 构建索引数据
    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", "tag" + 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);
    // 失败的记录可以持久化,稍后重试。

     

  4. 构建查询。
    // 构建查询
    JSONObject jsonObject = new JSONObject();
     
    // SearchParameter.QUERY对应用户输入,建议搜索域分词。
    // 这里假设用户输入是“天空”,要在"title", "tag"这两个域上发起搜索。
    JSONObject query = new JSONObject();
    query.put("天空", new JSONArray(Arrays.asList("title", "tag")));
    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", new JSONArray(Arrays.asList("白云")));
    filter2.put("ocr_text", new JSONArray(Arrays.asList("白云"))); // 一条索引只要在"tag"或者"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 latitudeObject = new JSONObject();
    latitudeObject.put(SearchParameter.LOWER, -40.0f);
    latitudeObject.put(SearchParameter.UPPER, 40.0f);
    jsonObject.put("latitude", latitudeObject); // 纬度必须在[-40.0f, 40.0f]
     
    JSONObject longitudeObject = new JSONObject();
    longitudeObject.put(SearchParameter.LOWER, -90.0);
    longitudeObject.put(SearchParameter.UPPER, 90.0);
    jsonObject.put("longitude", longitudeObject); // 经度必须在[-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("datetaken", SearchParameter.DESC);
    jsonObject.put(SearchParameter.ORDER_BY, order);
     
    // SearchParameter.GROUP_FIELD_LIST对应分组搜索的域,调用groupSearch接口需要指定。
    jsonObject.put(SearchParameter.GROUP_FIELD_LIST, new JSONArray(Arrays.asList("tag", "ocr_text")));
     
    // 得到查询字符串。
    String queryJsonStr = jsonObject.toString();
     
    // 构建的json字符串如下:
    /**
    {
        "SearchParameter.QUERY": {
            "天空": [
                "title",
                "tag"
            ]
        },
        "SearchParameter.FILTER_CONDITION": [
            {
                "bucket_id": [
                    0,
                    1,
                    2
                ],
                "id": [
                    0,
                    1
                ]
            },
            {
                "tag": [
                    "白云"
                ],
                "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",
            "datetaken": "DESC"
        },
        "SearchParameter.GROUP_FIELD_LIST": [
            "tag",
            "ocr_text"
        ]
    }
    **/

     

  5. 开始搜索会话,发起搜索。
    // 开始搜索会话
    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> searchResult = searchSession.search(queryJsonStr, i, batch);
            // 处理IndexData
        }
        int groupLimit = 10; // 每个分组域上最多返回10个分组结果
        List<Recommendation> recommendationResult = searchSession.groupSearch(queryJsonStr, groupLimit);
        // 处理Recommendation
    } finally {
        // 结束搜索,释放资源
        searchAbility.endSearch(SearchParameter.DEFAULT_GROUP, bundleName, searchSession);
    }

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值