
# 对接CSS提供云搜索服务
#### 背景信息
云搜索服务（Cloud Search Service，简称CSS），为您提供托管的分布式搜索引擎服务，完全兼容开源Elasticsearch搜索引擎，支持结构化、非结构化文本的多条件检索、统计、报表。云搜索服务的使用流程和数据库类似，更多介绍请参见[云搜索服务](https://support.huaweicloud.com/css/index.html)。
在AstroZero中，通过应用与CSS （Cloud Search Service）对接，实现云搜索服务功能。
#### 场景描述
使用云搜索服务创建索引。
 #### 前提条件
参照如下操作，获取CSS提供服务的URL地址。
1. 在云搜索服务控制台的左侧导航栏中，选择"集群管理"。
2. 在集群管理列表中，获取"内网访问地址"的值。
 
#### 新建CSS连接器
1. 参考[创建连接器入口](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_0653.html#astrozero_05_0653__section54416265268)中操作，进入创建连接器页面。
2. 在左侧列表中，选择"数据库 \> 云搜索"，单击"+"。 
   图1添加云搜索连接器   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001932887616.png "点击放大")
   
   
3. 设置CSS对接参数，单击"保存"。 
   图2设置CSS对接参数   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001960126341.png "点击放大")
   - 名称：连接器的名称。
   
   - 地址：CSS提供服务的URL地址，配置为[前提条件]中获取的值。
   
   - 版本：ElasticSearch的大版本号，目前支持版本6和7。
   
   - 安全模式：在安全模式访问集群时，将进行通讯加密及安全认证。安全模式下，若地址未指明协议，将默认使用https。
   
   - 使用证书：仅在使用https协议，且无法通过证书校验时，才需要使用自定义的证书。 该证书将用于构建客户端，以验证服务端的真实性，当前支持x509格式的证书。
     
   
   - 打包当前配置：默认为选中，对信息敏感的场景，建议不勾选。 选中该选项后，应用打包时会将当前配置的连接器信息一并打出。例如，如果应用包发布到运行环境，当前配置默认会被同步到运行环境中。
     
   
   
   
   
 
#### 在脚本中调用连接器
在脚本中，调用连接器实现与CSS的对接。
1. 参考[开发一个简单脚本实例](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_5031.html)中操作，创建一个空白脚本。
   
   图3新建一个空白脚本   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001933047016.png "点击放大")
   
   
2. 在脚本编辑器中，输入如下代码。 
   ```
   //导入该脚本所依赖的标准库文件。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('*NS__CSS1* ')中"*NS__CSS1*"为连接器的名称。
   
   
3. 单击脚本编辑器页面上方的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001933047008.png)，保存脚本。
4. 保存成功后，单击![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001932887632.png)，运行脚本。
5. 不用设置输入参数，直接单击测试窗口右上角的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001933047012.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)
   ```
   
   
7. 单击脚本编辑器页面上方的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001960126325.png)，启用脚本。
8. 在连接器详情页面的"相关脚本"中，单击"管理脚本"，将上一步启用的脚本拖入"已选择"区域，单击"保存"。 
   图4单击"管理脚本"   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001960286145.png "点击放大")
   图5选择脚本   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001960286141.png "点击放大")
   
   
9. 在连接器详情页面的"相关脚本"中，单击脚本操作列的![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001960286157.png)。
   
   在"索引"区域，可查看到脚本的执行结果，即添加了"indexname1"和"indexname2"索引。
   图6查看索引添加结果   
   ![](https://support.huaweicloud.com/usermanual-astrozero/zh-cn_image_0000001932887636.png "点击放大")
   
   
 
