
# 对接CSS实现在应用中调用分布式搜索
云搜索服务（Cloud Search Service，简称CSS），为您提供托管的分布式搜索引擎服务，完全兼容开源Elasticsearch搜索引擎，支持结构化、非结构化文本的多条件检索、统计、报表。在华为云Astro轻应用中，通过应用与CSS对接，实现云搜索服务功能。
#### 前提条件
参照如下操作，获取CSS提供服务的URL地址。
1. 登录[云搜索服务控制台](https://console.huaweicloud.com/elasticsearch/?locale=zh-cn)。
2. 在左侧导航栏中，选择"集群管理"。
3. 在集群管理列表中，获取"内网访问地址"的值。
 
 #### 费用说明
应用对接CSS连接器后，CSS服务需要单独付费，具体收费标准请参见[华为云定价](https://www.huaweicloud.com/pricing/index.html)。**应用停用后，CSS** **服务仍将按照既定的计费规则继续计费。如果不再使用该服务，请按照[停止计费](https://support.huaweicloud.com/price-css/css_01_0240.html)中操作及时退订实例，避免产生额外的费用。**
#### 新建CSS连接器
1. 参考[登录华为云Astro轻应用应用设计器](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9004.html)中操作，进入应用设计器。
2. 在左侧导航栏中，选择"集成"。
3. 单击"连接器"中的" 连接器实例"，进入连接器实例页面。
4. 在左侧导航栏中，选择"数据 \> 云搜索"。
5. 在右侧页面单击"+"，设置云搜索对接参数。 
   图1创建云搜索   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001988304428.png "点击放大")
   表1创建CSS连接器参数说明 
   | 参数       | 说明                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
   |:---|:---|
   | 名称       | 新建连接器的名称。命名要求如下： - 长度不能超过64个字符，包括前缀命名空间的长度。 名称前的内容为命名空间，在华为云Astro轻应用中为了避免不同租户间数据的重名，租户在首次创建应用时需要先定义一个命名空间。一个租户只能创建一个命名空间，创建后不支持修改。   - 必须以英文字母开头，只能由英文字母、数字或单下划线组成，且不能以下划线结尾。   |
   | 地址       | CSS服务的内网访问地址，配置为[费用说明]中获取的值。                                                                                                                                                                                                                                                                                                                                                                                               |
   | 版本       | ElasticSearch的版本号，目前支持版本6和7。                                                                                                                                                                                                                                                                                                                                                                                                                                        |
   | 安全模式     | 在安全模式访问集群时，将进行通讯加密及安全认证。安全模式下，若地址未指明协议，将默认使用https。                                                                                                                                                                                                                                                                                                                                                                                                                  |
   | 用户名      | 登录CSS的账号名，开启"安全模式"时，才会显示该参数。                                                                                                                                                                                                                                                                                                                                                                                                                                        |
   | 密码       | 登录CSS账号对应的密码，开启"安全模式"时，才会显示该参数。                                                                                                                                                                                                                                                                                                                                                                                                                                     |
   | 使用证书     | 仅在使用https协议，且无法通过证书校验时，才需要使用自定义的证书。                                                                                                                                                                                                                                                                                                                                                                                                                                 |
   | 证书       | 该证书用于构建客户端，以验证服务端的真实性，当前支持x509格式的证书。开启"使用证书"时，才会显示该参数。                                                                                                                                                                                                                                                                                                                                                                                                              |
   | 客户端证书    | 该证书用于服务端对客户端的校验，当前支持x.509格式的证书。开启"使用证书"时，才会显示该参数。                                                                                                                                                                                                                                                                                                                                                                                                                   |
   | 客户端私钥    | 该密钥用于客户端证书的解密。开启"使用证书"时，才会显示该参数。                                                                                                                                                                                                                                                                                                                                                                                                                                    |
   | 打包当前配置   | 选中该选项后，应用打包时会将当前配置的连接器信息一并打出。例如，如果应用包发布到运行环境，当前配置默认会被同步到运行环境中。如果不勾选，则内容不会打包发布到运行环境，此时需要您参考[管理应用中的连接器](https://support.huaweicloud.com/usermanual-astrozero/astrozero_06_2020.html)中操作，创建对应的连接器。 默认为选中，对信息敏感的场景，建议不勾选。                                                                                                                                                                                                            |
   | 索引添加租户标识 | 开启时，生成索引的名称和别名自动添加租户前缀（例如：租户标识--名称/别名）。                                                                                                                                                                                                                                                                                                                                                                                                                             |
      
   
   
6. 设置完成后，单击"保存"。
 
#### 在脚本中调用连接器
在事件中，调用连接器实现与CSS的对接。
1. 参考[创建空白华为云Astro轻应用脚本](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9162.html)中操作，创建一个空白脚本。
2. 在脚本编辑器中，输入如下代码，调用一个CSS连接器，并实现索引操作。 
   ```
   //导入该事件所依赖的标准库文件。es是系统预置的标准库。
   import * as es from 'es'
   /
      ES模块部分事件接口调用示例
   */
   let indexName1 = "indexName1"
   let indexName2 = "indexName2"
   let aliasName = "alias"
   let client = es.newClient('CSS1') //创建客户端需要输入连接器实例名称，这里举例为“CSS1”
   //1. 准备，如果已经存在索引，先进行删除（删除索引同时会删除索引内文档）
   let exist = client.checkIndexExist(indexName1)
   if (exist) { client.dropIndex(indexName1) }
   exist = client.checkIndexExist(indexName2)
   if (exist) { client.dropIndex(indexName2) }
   client.createIndex(indexName1) //创建一个没有映射的索引（根据插入的文档动态生成映射）
   //2. 插入或更新文档，如果已存在同id文档则更新，不存在则插入
   let doc = {
       "_id": "1001",     //自定义的文档ID，若不指定_id，则自动生成唯一随机的文档ID
       "foo": "apple",
       "bar": 30,
   }
   let docID = client.indexDoc(indexName1, doc) //返回index的文档id
   console.log("docID: ", docID) //此处docID为1001
   //3. 批量插入或更新文档
   let docs = [    //再定义两个文档
       {
           "_id": "1002",
           "foo": "banana",
           "bar": 40,
       },
       {
           "_id": "1003",
           "foo": "orange",
           "bar": 50,
           "baz": true,
       }
   ]
   client.bulkIndexDocs(indexName1, docs)
   //4. 局部更新文档
   client.updateDocByDocID(indexName1, "1001", {
       bar: 35,     //局部更新，只将bar字段改为35
       qux: "none",    //局部添加新字段和值
   })
   //5. 增删改之后可以显式调用refresh进行刷新，否则需等待约1秒之后，才可被搜
   client.refresh(indexName1)
   //6. 查记录数
   let count = client.countDocs(indexName1)
   console.log("count: ", count) //应打印3
   //7. 按条件查
   let condition = { 
       query: {
           range: {
               bar: { gte: 40 }
           }
       }
   }
   let searchRes = client.search(condition, indexName1)  //查询bar字段大于40的文档
   console.log("searchRes: ", searchRes)   //此处会打印出两个匹配的文档
   //8. 按条件更新
   let script = 'ctx._source.bar = 70' 
   let query = {
       match: {
           foo: "apple",
       }
   }
   let updatedCount = client.updateByQuery(indexName1, query, script) //批量更新，把foo为apple的文档的bar都变为70
   console.log("updatedCount: ", updatedCount) //打印出改动的文档数量，此处打印1
   client.refresh(indexName1)
   //9. 仅查询id列表
   let idList = client.searchIDList(indexName1, {
       query: {
           match_all: {}   //全部查询
       },
       size: 5  //指定最多搜出5个结果
   })
   console.log("idList: ", idList) //会打印 ["1001","1002","1003"]
   //10. 轻量查询(相比于search，query不需要写json条件，只需要简单字符串查询即可)
   let queryRes = client.query("foo:apple", false, indexName1) //查询foo字段为apple的文档, 第二个参数false表示只查前十个文档，为true则为全查
   console.log("queryRes1: ", queryRes) //会有1个查询结果
   queryRes = client.query("foo:apple OR banana", false, indexName1) //除了foo字段为apple的文档，再加上全文查询banana的结果
   console.log("queryRes2: ", queryRes) //会有2个查询结果
   //11. 创建第二个索引，自定义映射
   let mp = {
       dynamic: "strict",
       properties: {
           name: { type: "text"    },
           age: {  type: "integer" }
       }
   }
   client.createIndexWithMapping(indexName2, mp)
   //12. 获得索引的映射
   let mpRes = client.getMapping(indexName2)
   console.log("mapping: ", mpRes)    //打印出映射
   //13. 绑定别名
   client.attachAlias(indexName1, aliasName)
   //14. 对别名操作和对索引操作一致
   client.deleteDocByDocID(aliasName, "1001")
   client.refresh(aliasName)
   count = client.countDocs(aliasName)
   console.log("countAfterDelete: ", count) //这里会打印2
   //15. 得到别名关联的索引
   let attached = client.getAttachedIndexes(aliasName)
   console.log(attached)   //这里会打印出indexName1
   //16. 得到索引管理的别名
   let ali = client.getAlias(indexName1)
   console.log(ali)    //打印出alias的名字
   //17. 同时绑定新索引，解绑旧索引
   client.attachAndDetachAlias(indexName2, indexName1, aliasName)
   attached = client.getAttachedIndexes(aliasName)
   console.log(attached)   //打印出indexName2
   //18. 获取当前所有索引的基本信息(对应的别名、文档数)
   let catRes = client.cat()
   console.log("catRes: ", catRes)
   ```
   其中，es.newClient('*命名空间__CSS1* ')中"*命名空间__CSS1*"为连接器的名称。
   
   
3. 单击脚本编辑器页面上方的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001894299448.png)，保存脚本。
4. 保存成功后，单击![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001894299420.png)，运行脚本。
5. 不用设置输入参数，直接单击测试窗口右上角的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001894139540.png)。
6. 在日志页签，可查看到创建了索引。 
   ```
   0826 10:20:14.685|debug|vm[86]>>> AstroZero 1.2.8 - Production on 2019-08-23 14:44:06 2ce004a222b087e3ac55c70d4e2482d7338d81aa debug (<unknown>.ts:0)
   0826 10:20:14.685|debug|vm[86]>>> script: Test_CSS1 1.0.1  (<unknown>.ts:0)
   0826 10:20:14.685|debug|vm[86]>>> locale: zh_CN (<unknown>.ts:0)
   0826 10:20:14.685|debug|vm[86]>>> timezone: (GMT+00:00) Greenwich Mean Time (GMT) (<unknown>.ts:0)
   0826 10:20:14.766|debug|vm[86]>>> docID:  1001 (Test_CSS1.ts:28)
   0826 10:20:14.812|debug|vm[86]>>> count:  3 (Test_CSS1.ts:57)
   0826 10:20:14.815|debug|vm[86]>>> searchRes:  {
       "aggregations": {},
       "hits": [
           {
               "_id": "1002",
               "_index": "indexname1",
               "_score": 1,
               "_source": {
                   "bar": 40,
                   "foo": "banana"
               },
               "_type": "_doc"
           },
           {
               "_id": "1003",
               "_index": "indexname1",
               "_score": 1,
               "_source": {
                   "bar": 50,
                   "baz": true,
                   "foo": "orange"
               },
               "_type": "_doc"
           }
       ],
       "max_score": 1,
       "total": {
           "relation": "eq",
           "value": 2
       }
   } (Test_CSS1.ts:68)
   0826 10:20:14.82|debug|vm[86]>>> updatedCount:  1 (Test_CSS1.ts:78)
   0826 10:20:14.831|debug|vm[86]>>> idList:  [
       "1002",
       "1003",
       "1001"
   ] (Test_CSS1.ts:88)
   0826 10:20:14.833|debug|vm[86]>>> queryRes1:  {
       "_id": "1001",
       "_index": "indexname1",
       "bar": 70,
       "foo": "apple",
       "qux": "none"
   } (Test_CSS1.ts:92)
   0826 10:20:14.835|debug|vm[86]>>> queryRes2:  {
       "_id": "1002",
       "_index": "indexname1",
       "bar": 40,
       "foo": "banana"
   },
   {
       "_id": "1001",
       "_index": "indexname1",
       "bar": 70,
       "foo": "apple",
       "qux": "none"
   } (Test_CSS1.ts:94)
   0826 10:20:14.879|debug|vm[86]>>> mapping:  {
       "age": {
           "type": "integer"
       },
       "name": {
           "type": "text"
       }
   } (Test_CSS1.ts:108)
   0826 10:20:14.898|debug|vm[86]>>> countAfterDelete:  2 (Test_CSS1.ts:117)
   0826 10:20:14.899|debug|vm[86]>>> indexname1 (Test_CSS1.ts:121)
   0826 10:20:14.899|debug|vm[86]>>> alias (Test_CSS1.ts:125)
   0826 10:20:14.908|debug|vm[86]>>> indexname2 (Test_CSS1.ts:130)
   0826 10:20:14.912|debug|vm[86]>>> catRes:  [
       {
           "indexName": "indexname1",
           "aliases": null,
           "docCount": 2
       },
       {
           "indexName": "indexname2",
           "aliases": [
               "alias"
           ],
           "docCount": 0
       }
   ] (Test_CSS1.ts:134)
   ```
   
   
 
