前几天申请了阿里云开放云搜索(Aliyun OpenSearch)的邀请码,今早通过收到通过验证了,于是准备试试云搜索。
阿里云搜索使用很简单,和Lucene一样,包括索引文档字段几个概念。每个索引可以当成数据库的一个数据库,一条文档当成数据库的一条记录,一个字段就是数据库的一个字段。
目前支持四种形式的搜索模板,资讯类,小说类,应用类和社区类。模板在这儿就是规定好了索引的字段,也可以自定义。详细介绍
我想测试一下,就把自己的博客写的这十几篇POST发上去建立索引吧,使用了资讯类的模板。
模板字段如下:字段名 | 类型 | 字段说明 | 独立检索 | 可检索 | 可排序 | 可筛选 |
id | STRING | 文档标识(必选) | 是 | |||
title | TEXT | 资讯标题 | 是 | 是 | ||
body | TEXT | 资讯内容 | 是 | |||
type_id | UINT16 | 类型,如财经 | 是 | |||
cat_id | UINT16 | 组别,支持多个,如"cat_id":[12, 13]、"cat_id":["12", "13"],具体请参加模版数据类型说明 | 是 | |||
url | STRING | 展示url | ||||
author | TEXT | 作者 | 是 | 是 | ||
thumbnail | STRING | 缩略图 | ||||
source | TEXT | 新闻来源 | 是 | |||
create_timestamp | UINT32 | 创建时间 | 是 | 是 | ||
update_timestamp | UINT32 | 更新时间 | 是 | 是 | ||
hit_num | UINT32 | 点击数 | 是 | 是 | ||
focus_count | UINT32 | 关注数 | 是 | 是 | ||
grade | UINT32 | 读者评分 | 是 | 是 | ||
comment_count | UINT32 | 评论数 | 是 | 是 | ||
boost | INT8 | 站长自定义加分项 | 是 | 是 | ||
integer_1 | UINT32 | 保留字段,站长自定义 | 是 | 是 | ||
integer_2 | UINT32 | 保留字段,站长自定义 | 是 | 是 | ||
integer_3 | UINT32 | 保留字段,站长自定义 | 是 | 是 | ||
tag | TAG | 标签 | 是 | |||
display_text | STRING | 站长自定义展示字段 |
提供的需要上传的JSON格式示例:
[ { "fields": { "body": "广大中小企业都有各种结构化的数据需要进行检索,目前一般采用数据库本身提供的搜索功能或者利用open source的搜索软件搭建", "display_text": "open search", "hit_num": "88888", "update_timestamp": "1345448016", "type_id": "1", "url": "http://www.aliyun.com", "cat_id": [1,2], "author": "阿里云", "grade": "10", "comment_count": "1234", "tag": {"搜索":10,"阿里云":2,"云搜索":5,"开放搜索":8}, "source": "阿里云云搜索", "focus_count": "8888", "title": "阿里云隆重推出开放搜索", "boost": "1", "id": "id_1", "integer_1": "100", "create_timestamp": "1345448016" }, "cmd": "ADD" }, ... ]
其中很多字段用不上,可以忽略。我的博客都是在jekyll中的post类型,需要把所有的post转为JSON格式。我写了一个Python,来处理_post文件夹下面的所有文章,最后导出Json
#coding=utf-8 ''' 将jekyll中_post目录下的文章到处json格式,用于阿里云搜索 @author: gudaihui ''' import os import re import json import time def object2dict(obj): '''使用内置json转换时,需要将对象转为dict''' #convert object to a dict d = {} d.update(obj.__dict__) return d class PostInfo(): '''存储一条博客的所有字段类''' def __init__(self, title, tags, content, rooturl, f): self.title = title self.tag = {} #标签有一个权重,默认都为1 for t in tags.split(","): self.tag[t.strip()] = 1 self.body = content self.id = f.replace("-", "").replace(".html", "") self.display_text = "open search" self.hit_num = "88888" #处理日期和URL t = re.match('\\d{4}-\\d{2}-\\d{2}', f).group() self.url = rooturl + f.replace(t + "-", (t + "-").replace("-", "/")) self.update_timestamp = "%d" % time.mktime(time.strptime(t,'%Y-%m-%d')) self.create_timestamp = "%d" % time.mktime(time.strptime(t,'%Y-%m-%d')) self.type_id = "1" self.cat_id= [1,2] self.author="yhzhtk" self.grade="10" self.source="yhzhtk" self.boost = "1" def getPostInfo(path, rooturl="http://yhzhtk.info/"): '''从文件中读取所有的POST返回PostInfo信息''' os.chdir(path) posts = [[open(f, "r").read(), f] for f in os.listdir(path) if f.endswith(".html")] pattern = re.compile(r"---\nlayout: post\ntitle: ([^\n]*)\ntags: \[([^\]]*)\]\n---\n(.*)", re.DOTALL) infos = [] for post, f in posts: match = pattern.match(post) if match: title = match.group(1) tags = match.group(2) content = match.group(3) content = re.sub("<[^>]*>","",content) content = re.sub("{%[^%]*%}","",content) content = content.replace("\n", "") infos.append(PostInfo(title, tags, content, rooturl, f)) return infos def genPostJson(infos): '''将PostInfo处理得到最后的Json''' jsonstr = "" for info in infos: temp = json.dumps(info, ensure_ascii=False, default=object2dict) temp = '''{"fields":''' + temp + ''', "cmd": "ADD"}''' jsonstr += "," + temp if json: jsonstr = jsonstr[1:] jsonstr = "[" + jsonstr + "]" print jsonstr if __name__ == '__main__': '''开始执行''' path = r"C:\Documents and Settings\yicha\blog\_posts" infos = getPostInfo(path) genPostJson(infos);
所有的json是直接输出了,也可以输出到一个文件中。然后将文件上传到刚才新建的索引中。刷新,看到文档条数不为0,就可以点击搜索测试了,如果数量仍为0,可以查看错误日志,里面写明了错误的文档和错误原因。最后,可以通过给的API把搜索功能添加到你的产品中。
搜索的效率问题现在还没法知道,因为文档数比较少。等有机会可以应用到实际中测测。