本文介绍本地搜索功能、使用方法和示例代码。

搜索功能概述

AIMSDK中,消息和会话的搜索是基于本地数据的搜索,目前不支持服务端搜索,因此AIMSDK的搜索能力有以下几个特点:
  • 仅支持本地搜索,可搜索范围受到本地数据库存储消息和会话多少的限制。
  • 应用重装后首次登录,AIMSDK会拉取首屏会话及每条会话的最后一条消息(last message),该场景下,仅可搜索到首屏可看到的会话及消息。
  • AIMSDK支持多账号同时登录,搜索服务与账号绑定,即每个搜索服务仅能搜索本账号对应的消息和会话。
  • 搜索引擎采用分词进行搜索。
    • 对于英文或数字:以空格或标点符号作为分词进行搜索。

      例如:123,abc,可通过“12”或者“ab”进行搜索,“23”、 “bc”无法搜出该消息。

    • 对于中文:每个汉字都可进行搜索。

      例如:你好钉钉,可通过“你”、“好钉”、“钉钉”搜出该消息。

  • 对于消息搜索,默认情况下仅可对文本消息进行搜索,其他类型消息如需参与搜索,需进行特殊处理。
搜索功能列表如下:
  • 搜索纯文本消息
  • 搜索消息并按照会话进行聚合
  • 搜索群名称
  • 搜索内容分页
  • 自定义搜索非文本消息
  • 按照类型搜索消息

使用方法

  • 获取搜索服务

    imModule:GetSearchService()

    • manager与用户绑定,通过engine获取。
    • 搜索服务与manager(用户)绑定,只能搜索本用户的本地消息。
    • 所有的搜索能力通过该Service进行提供。
  • 消息搜索
    项目 描述
    API SearchChatContent
    功能概述 通过关键字进行消息搜索。
    过滤条件 消息创建时间范围、排序,指定单个或多个会话、发送方、消息类型。
    返回 消息体,高亮位置信息。
  • 消息搜索,并按照会话聚合
    项目 描述
    API SearchConversationByContent
    功能概述 通过关键字进行消息搜索,并按照会话聚合返回。
    过滤条件 消息创建时间范围、排序,指定单个或多个会话、发送方、消息类型。
    返回 会话列表,包含会话信息及首条消息。
  • 群名称搜索
    项目 描述
    API SearchGroupByName
    功能概述 通过关键字进行群名称搜索。
    过滤条件 群创建时间范围、排序。
    返回 群列表

搜索功能实现示例

纯文本消息的搜索
  AIMSearchChatContentParams params;
  params.offset = 0; // 从第0个开始获取
  params.max_num = 20; // 最多获取20个
  params.start_time = 1582709555; // 搜索消息开始时间,未指定则从0开始
  params.end_time = 1582709555; // 搜索消息开始时间,未指定则到现在
  // 是否自动高亮关键字,返回的AIMSearchHighlightRange包含高亮位置信息
  params.is_auto_highlight = true; 
  params.keyword = "ding"; // 搜索关键字
  params.is_asc = false; // 按时间倒序搜索
  params.cids = {"cid_1", "cid2"}; // 可选:搜索的会话范围
  params.sender_ids = {user_1, user_2}; // 可选:指定消息发送者搜索
  aim_search_service_ex->SearchChatContent(
      params,
      [&ev, &expected_results](const std::vector<AIMSearchChatResult>& results,
                               int32_t total_size) {     
         // total_size 仅在offset = 0 时有效,即第一页     
      },
      [&ev](const AIMError& error) {
      });
  • keyword必须指定,其他搜索条件可选。
  • 参数的offset、max_num以及返回的total_size用于结果分页。
  • AIMSearchChatResult中包含消息及高亮位置。
搜索消息并按照会话进行聚合返回
  AIMSearchChatContentParams params;
  params.keyword = "keyword";
  params.is_asc = true;
  aim_search_service_ex->SearchConversationByContent(
      params,
      [&ev, time](const std::vector<AIMSearchConversationResult>& results,
                  int32_t total_size) {
         // total_size 仅在offset = 0 时有效,即第一页
      },
      [&ev](const AIMError& error) {
        ev.Signal();
        ASSERT_TRUE(false);
      });
  • 返回的AIMSearchConversationResult中包含会话及一条消息。
  • 该条消息不保证是按时间排序的第一条。
群名称搜索
  AIMSearchGroupParams params;
  params.keyword = "keyword";
  aim_search_service_ex->SearchGroupByName(
      params,
      [&ev, time](const std::vector<AIMConversation>& results,
                  int32_t total_size) {
         // total_size 仅在offset = 0 时有效,即第一页
      },
      [&ev](const AIMError& error) {
        ev.Signal();
        ASSERT_TRUE(false);
      });
非文本消息的搜索

非文本消息包含图片,语音,结构化,自定义消息等,如需参与搜索,需要对消息进行预处理。

如对语音的识别,图像识别,自定义卡片的识别等,需要App侧对此类消息可搜索字段进行加工处理。

处理方法如下:

  class MyListener : public AIMMsgListener {
   public:
    MyListener(AIMMsgServicePtr service) {
        service_ = service;
    }

    // 当新消息入库时,进行消息的再加工处理,更新可搜索字段
    void OnStoredMessages(const std::vector<AIMMessage>& msgs) {
      std::vector<AIMMsgBizUpdateInfo> infos;
      for (const auto& msg : msgs) {
        if (message.content.content_type ==
                      AIMMsgContentType::CONTENT_TYPE_AUDIO) {
          AIMMsgBizUpdateInfo info;
          info.cid = msg.cid;
          info.localid = msg.localid;
          info.update_mode = AIMMsgUpdateMode::UPDATE_BIZ_ALL;
          info.biz_info.biz_tag = "to_me";
          info.biz_info.biz_text = "text from voice";
          infos.push_back(info);
        } else {
            // Other msgs...
        }
      }
      service_->UpdateLocalMessagesBizInfo(
          infos, []() {}, [](const AIMError& error) {});
    }
    void OnRemovedMessages(const std::vector<AIMMessage>& msgs) {}
    void OnAddedMessages(const std::vector<AIMNewMessage>& msgs) {}

   private:
  };
  std::shared_ptr<MyListener> listener =
      std::make_shared<MyListener>(msg_service);
  msg_service->AddMsgListener(listener);
  • 需要监听消息的入库回调,对需要的消息进行加工处理。
  • 对于历史消息,需要手动拉取消息,并进行处理。
    注意 在版本更新时需特别注意。
  • 消息的可加工字段位biz_tag及biz_text。
    • biz_tag:用于指定业务类型,作为搜索条件。
    • biz_text: 用于指定搜索文本,作为搜索匹配内容。
  • biz_tag及biz_text仅存储在本地,不会上传到服务端。

开始搜索:

  AIMSearchChatContentParams params;
  params.keyword = "text from voice"; // 搜索关键字
  // 搜索文本及语音类型消息
  params.support_msg_types = {AIMMsgContentType::CONTENT_TYPE_AUDIO, 
                              AIMMsgContentType::CONTENT_TYPE_TEXT};
  aim_search_service_ex->SearchChatContent(
      params,
      [&ev, &expected_results](const std::vector<AIMSearchChatResult>& results,
                               int32_t total_size) {     
         // total_size 仅在offset = 0 时有效,即第一页     
      },
      [&ev](const AIMError& error) {
      });
按照消息类型搜索消息
  AIMSearchChatContentParams params;
  // 找出图片
  params.support_msg_types = {AIMMsgContentType::CONTENT_TYPE_IMAGE};
  // 找出自定义消息
  // params.support_msg_types = {AIMMsgContentType::CONTENT_TYPE_CUSTOM};
  // params.support_sub_types = {1, 2}; // 消息子类型
  params.cids = {"cid_1"}; // 仅搜索该会话内的消息
  aim_search_service_ex->SearchChatContent(
      params,
      [&ev, &expected_results](const std::vector<AIMSearchChatResult>& results,
                               int32_t total_size) {     
         // total_size 仅在offset = 0 时有效,即第一页     
      },
      [&ev](const AIMError& error) {
      });
搜索内容分页

以20条为一页。

// 获取第一页
  int32_t page_count;
  AIMSearchChatContentParams params;
  params.offset = 0; // 从第0个开始获取
  params.max_num = 20; // 最多获取20个
  aim_search_service_ex->SearchChatContent(
      params,
      [&ev, &expected_results, &page_count](const std::vector<AIMSearchChatResult>& results,
                               int32_t total_size) {     
          // total_size 为总个数
          page_count = total_size / 20;
          if (page_count % 20 > 0) {
              page_count++;
          }
      },
      [&ev](const AIMError& error) {
      });

// 获取第2页
  params.offset = 20 * 1; // 从第0个开始获取
  params.max_num = 20; // 最多获取20个
  aim_search_service_ex->SearchChatContent(
      params,
      [&ev, &expected_results, &page_count](const std::vector<AIMSearchChatResult>& results,
                               int32_t total_size) {     
          // total_size 可以忽略
      },
      [&ev](const AIMError& error) {
      });