Archive for 七月, 2008

企业级搜索引擎Solr使用入门指南

    由于搜索引擎功能在门户社区中对提高用户体验有着重在门户社区中涉及大量需要搜索引擎的功能需求,目前在实现搜索引擎的方案上有集中方案可供选择:

  • 基于Lucene自己进行封装实现站内搜索。

工作量及扩展性都较大,不采用。

  • 调用Google、Baidu的API实现站内搜索

同第三方搜索引擎绑定太死,无法满足后期业务扩展需要,暂时不采用。

  • 基于Compass+Lucene实现站内搜索

    适合于对数据库驱动的应用数据进行索引,尤其是替代传统的like ‘%expression%’来实现对varchar或clob等字段的索引,对于实现站内搜索是一种值得采纳的方案。但在分布式处理、接口封装上尚需要自己进行一定程度的封装,暂时不采用。

  • 基于Solr实现站内搜索

封装及扩展性较好,提供了较为完备的解决方案,因此在门户社区中采用此方案,后期加入Compass方案。

1、 Solr简介

    Solr是一个基于Lucene的Java搜索引擎服务器。Solr 提供了层面搜索、命中醒目显示并且支持多种输出格式(包括 XML/XSLT 和 JSON 格式)。它易于安装和配置,而且附带了一个基于 HTTP 的管理界面。Solr已经在众多大型的网站中使用,较为成熟和稳定。Solr 包装并扩展了 Lucene,所以Solr的基本上沿用了Lucene的相关术语。更重要的是,Solr 创建的索引与 Lucene 搜索引擎库完全兼容。通过对 Solr 进行适当的配置,某些情况下可能需要进行编码,Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。此外,很多 Lucene 工具(如Nutch、 Luke)也可以使用 Solr 创建的索引。

2、 Tomcat下Solr安装配置

    由于Solr基于java开发,因此Solr在windows及Linux都能较好部署使用,但由于Solr提供了一些用于测试及管理、维护较为方便的shell脚本,因此在生产部署时候建议安装在Linux上,测试时候可以在windows使用。

下面以Linux下安装配置Solr进行说明,windows与此类似。

wget http://apache.mirror.phpchina.com/tomcat/tomcat-6/v6.0.16/bin/apache-tomcat-6.0.16.zip

unzip apache-tomcat-6.0.16.zip

mv apache-tomcat-6.0.16 /opt/tomcat

chmod 755 /opt/tomcat/bin/*

wget http://apache.mirror.phpchina.com/lucene/solr/1.2/apache-solr-1.2.0.tgz

tar zxvf apache-solr-1.2.0.tgz

Solr的安装配置最为麻烦的是对solr.solr.home的理解和配置,主要有三种

  • 基于当前路径的方式

cp apache-solr-1.2.0/dist/apache-solr-1.2.0.war /opt/tomcat/webapps/solr.war

mkdir /opt/solr-tomcat

cp -r apache-solr-1.2.0/example/solr/ /opt/solr-tomcat/

cd /opt/solr-tomcat

/opt/tomcat/bin/startup.sh

由于在此种情况下(没有设定solr.solr.home环境变量或JNDI的情况下),Solr查找./solr,因此在启动时候需要切换到/opt/solr-tomcat

  • 基于环境变量solr.solr.home

在当前用户的环境变量中(.bash_profile)或在/opt/tomcat/catalina.sh中添加如下环境变量

export JAVA_OPTS="$JAVA_OPTS -Dsolr.solr.home=/opt/solr-tomcat/solr"

  • 基于JNDI配置

mkdir –p /opt/tomcat/conf/Catalina/localhost

touch /opt/tomcat/conf/Catalina/localhost/solr.xml ,内容如下:

      <Context docBase="/opt/tomcat/webapps/solr.war" debug="0" crossContext="true" >
                 <Environment name="solr/home" type="java.lang.String" value="/opt/solr-tomcat/solr" override="true" />
    </Context>

访问solr管理界面

http://ip:port/solr

3、 Solr原理

clip_image002

    Solr对外提供标准的http接口来实现对数据的索引的增加、删除、修改、查询。在 Solr 中,用户通过向部署在servlet 容器中的 Solr Web 应用程序发送 HTTP 请求来启动索引和搜索。Solr 接受请求,确定要使用的适当SolrRequestHandler,然后处理请求。通过 HTTP 以同样的方式返回响应。默认配置返回 Solr 的标准 XML 响应,也可以配置 Solr 的备用响应格式。

可以向 Solr 索引 servlet 传递四个不同的索引请求:

  • add/update 允许向 Solr 添加文档或更新文档。直到提交后才能搜索到这些添加和更新。
  • commit 告诉 Solr,应该使上次提交以来所做的所有更改都可以搜索到。
  • optimize 重构 Lucene 的文件以改进搜索性能。索引完成后执行一下优化通常比较好。如果更新比较频繁,则应该在使用率较低的时候安排优化。一个索引无需优化也可以正常地运行。优化是一个耗时较多的过程。
  • delete 可以通过 id 或查询来指定。按 id 删除将删除具有指定 id 的文档;按查询删除将删除查询返回的所有文档。

一个典型的Add请求报文

<add>

<doc>

  <field name="id">TWINX2048-3200PRO</field>

  <field name="name">CORSAIR  XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory – Retail</field>

  <field name="manu">Corsair Microsystems Inc.</field>

  <field name="cat">electronics</field>

  <field name="cat">memory</field>

  <field name="features">CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader</field>

  <field name="price">185</field>

  <field name="popularity">5</field>

  <field name="inStock">true</field>

</doc>

<doc>

  <field name="id">VS1GB400C3</field>

  <field name="name">CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory – Retail</field>

  <field name="manu">Corsair Microsystems Inc.</field>

  <field name="cat">electronics</field>

  <field name="cat">memory</field>

  <field name="price">74.99</field>

  <field name="popularity">7</field>

  <field name="inStock">true</field>

</doc>

</add>

一个典型的搜索结果报文:

<response>

    <lst name="responseHeader">

        <int name="status">0</int>

        <int name="QTime">6</int>

        <lst name="params">

            <str name="rows">10</str>

            <str name="start">0</str>

            <str name="fl">*,score</str>

            <str name="hl">true</str>

            <str name="q">content:"faceted browsing"</str>

        </lst>

    </lst>

    <result name="response" numFound="1" start="0" maxScore="1.058217">

        <doc>

            <float name="score">1.058217</float>

            <arr name="all">

                <str>http://localhost/myBlog/solr-rocks-again.html</str>

                <str>Solr is Great</str>

                <str>solr,lucene,enterprise,search,greatness</str>

                <str>Solr has some really great features, like faceted browsing

                and replication</str>

            </arr>

            <arr name="content">

                <str>Solr has some really great features, like faceted browsing

                and replication</str>

            </arr>

            <date name="creationDate">2007-01-07T05:04:00.000Z</date>

            <arr name="keywords">

                <str>solr,lucene,enterprise,search,greatness</str>

            </arr>

            <int name="rating">8</int>

            <str name="title">Solr is Great</str>

            <str name="url">http://localhost/myBlog/solr-rocks-again.html</str>

        </doc>

    </result>

    <lst name="highlighting">

        <lst name="http://localhost/myBlog/solr-rocks-again.html">

            <arr name="content">

                <str>Solr has some really great features, like <em>faceted</em>

                <em>browsing</em> and replication</str>

            </arr>

        </lst>

    </lst>

</response>

关于solr的详细使用说明,请参考

http://wiki.apache.org/solr/FrontPage

4、 Solr测试使用

Solr的安装包包含了相关的测试样例,路径在apache-solr-1.2.0/example/exampledocs

  • 使用shell脚本(curl)测试Solr的操作:

cd apache-solr-1.2.0/example/exampledocs

vi post.sh,根据tomcat的ip、port修改URL变量的值URL=http://localhost:8080/solr/update

./post.sh *.xml                 # 
  • 使用Solr的java 包测试Solr的操作:

查看帮助:java -jar post.jar –help

提交测试数据:

java -Durl=http://localhost:8080/solr/update -Ddata=files -jar post.jar  *.xml      

 

下面以增加索引字段liangchuan、url为例,说明一下Solr中索引命令的使用

1) 修改solr的schema,配置需要索引字段的说明:

vi /opt/solr-tomcat/solr/conf/schema.xml ,在<fields>中增加如下内容

   <field name="liangchuan"  type="string" indexed="true" stored="true"/>

   <field name="url"  type="string" indexed="true" stored="true"/>

2) 创建增加索引请求的xml测试文件

touch /root/apache-solr-1.2.0/example/exampledocs/liangchuan.xml,内容如下:

<add>

<doc>

  <field name="id">liangchuan000</field>

  <field name="name">Solr, the Enterprise Search Server</field>

  <field name="manu">Apache Software Foundation</field>

  <field name="liangchuan">liangchuan’s solr "hello,world" test</field>

  <field name="url">http://www.google.com</field>

</doc>

</add>

3) 提交索引请求

cd apache-solr-1.2.0/example/exampledocs

    ./post.sh liangchuan.xml
    

4) 查询

通过solr的管理员界面http://localhost:8080/solr/admin查询

或通过curl 测试:

       export URL="http://localhost:8080/solr/select/"
       curl "$URL?indent=on&q=liangchuan&fl=*,score"
 

5、Solr查询条件参数说明

 
参数 描述 示例
q Solr 中用来搜索的查询。可以通过追加一个分号和已索引且未进行断词的字段的名称来包含排序信息。默认的排序是 score desc,指按记分降序排序。

q=myField:Java AND otherField:developerWorks; date asc

此查询搜索指定的两个字段并根据一个日期字段对结果进行排序。

start 将初始偏移量指定到结果集中。可用于对结果进行分页。默认值为 0。

start=15

返回从第 15 个结果开始的结果。

rows 返回文档的最大数目。默认值为 10。 rows=25
fq

提供一个可选的筛选器查询。查询结果被限制为仅搜索筛选器查询返回的结果。筛选过的查询由 Solr 进行缓存。它们对提高复杂查询的速度非常有用。

任何可以用 q 参数传递的有效查询,排序信息除外。
hl 当 hl=true 时,在查询响应中醒目显示片段。默认为 false。参看醒目显示参数上的 Solr Wiki 部分可以查看更多选项 hl=true
fl 作为逗号分隔的列表指定文档结果中应返回的 Field 集。默认为 “*”,指所有的字段。“score” 指还应返回记分。

*,score

   其中关于Solr查询相关的参数详细的信息请参看:
   http://wiki.apache.org/solr/CommonQueryParameters

    Solr的查询条件参数q的格式与Lucene相同,具体参看:

      http://lucene.apache.org/java/docs/queryparsersyntax.html

6、 在门户社区中solr使用模式

在门户社区中需要使用solr,可采用如下模式:

  • 对原有系统已有的数据或需要索引的数据量较大的情况

    直接采用通过http方式调用solr的接口方式,效率较差,采用solr本身对csv 的支持(http://wiki.apache.org/solr/UpdateCSV

),将数据导出为csv格式,然后调用solr的csv接口http://localhost:8080/solr/update/csv
  • 对系统新增的数据

    先将需要索引查询的数据组装成xml格式,然后使用httpclient 将数据提交到solr 的http接口,例如    

        http://localhost:8080/solr/update

   也可以参考post.jar中的SimplePostTool的实现。
http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/SimplePostTool.java?view=co
  • 中文分词

    采用庖丁解牛作为solr(Lucene)缺省的中文分词方案

    项目库:http://code.google.com/p/paoding/

    Google groups:http://groups.google.com/group/paoding

    Javaeye的groups:http://analysis.group.javaeye.com/

  • 与nutch的集成使用

    http://blog.foofactory.fi/2007/02/online-indexing-integrating-nutch-with.html

  • 嵌入式Solr

    http://wiki.apache.org/solr/Solrj#EmbeddedSolrServer

  • 分布式索引

    http://wiki.apache.org/solr/CollectionDistribution

7、参考资料

http://wiki.apache.org/solr/

http://www.ibm.com/developerworks/cn/java/j-solr1/

http://www.ibm.com/developerworks/cn/java/j-solr2/

http://www.xml.com/pub/a/2006/08/09/solr-indexing-xml-with-lucene-andrest.html?page=1

http://lucene.apache.org/java/docs/queryparsersyntax.html

http://www.blogjava.net/RongHao/archive/2007/11/06/158621.html

 

Technorati Tags: ,,,

无线互联网门户社区核心数据模型设计思考1

    根据典型的web2.0 sns门户社区,设计了无线互联网门户社区初步的核心数据模型。

    基本设计重点:

1、 以用户为中心,为用户提供综合性、一体化的社区体验

架构模型涵盖典型的web2.0社区的各种基本元素,包括:

  • 标签(tag)、标签云(tag cloud)
  • RSS(web订阅、邮件订阅、基于IM机器人的订阅)
  • IM
  • 用户群组
  • 微博客(twitter)、博客(Blog)
  • 点评(digg)、投票、话题、推荐、收藏夹
  • 用户点击行为分析(内容过滤、协同过滤)
  • 用户上传及分享
  • 社区搜索
  • Mashup(外部应用聚合)
  • 开放API

其中IM、用户关系链元素的设计在单独域模型中设计。

2、 基于真实关系链的无线互联网社区

    Facebook及国内诸如校内、海内这样SNS的无比风光,说明了基于相对真实关系链的价值。用户使用SNS的关注点大部分是希望维系和拓展现有的关系链,而不是重构关系链,因此SNS及IM不应当让用户抛弃现有的关系链去重新构造一个全新的关系链。要让用户导入现有的关系链到社区核心在于能够标识用户相对真实的身份及围绕此身份所形成的关系链。

    在互联网时代能够标识用户身份及用户关系链的东西包含如下一些:手机号码通信录、多IM通信录(QQ、MSN等联系人)、邮箱通信录。

    而号码同步+多IM协议集成及相关应用的结合,基本上涵盖了如上内容。

  • 手机号码通信录:客户端基于syncml协议的同步功能本身解决了此问题。
  • 多IM通信录:在用户使用客户端的多协议的IM功能登录QQ、MSN等IM时候,实际上无形之中就导入了其IM的联系人通信录
  • 邮箱通信录:通过Push Mail功能及RSS的邮件定于、绑定邮箱等功能就导入了邮箱通信录

3、 投其所好的过滤引擎

    门户社区成功最为核心的是用户体验。

   用户体验涉及方方面面,但一个与技术相关的至关重要的是能够根据用户的喜好、点击行为及消费行为,向用户推荐较为准确内容及好友。在设计上考虑了两种过滤引擎的实现需求,包括:基于内容的过滤(Content Based Filtering)、基于相似用户群体的兴趣的协同过滤(Collaborative Filtering)引擎。

    在数据模型设计上提供了多维度的数据采集数据采集方法,如Tag标签、Digg数、推荐、用户打分等等。

    构建无线互联网社区所必须的其他元素的架构及数据模型设计逻辑,继续考虑中。

手软门户域数据模型设计

 

手机客户端IM技术实现思考

手软客户端技术预研说明

 

Jabber协议分析之Subscriptions运行机制-Presence subscription

    手机客户端需要实现即时通信功能,在通信协议上采用开放的Jabber(XMPP)协议,整个XMPP协议最为核心也是最为复杂的部分是Subscription的运行机制,抓取了一下相关的通信协议报文,供开发时候参考。

  

1. 测试环境

1.1. 测试软件环境:

    Jabber服务器:Openfire 3.5.2

    Jabber客户端:Spark 2.5.8

抓包:Wireshark

1.2. 服务器环境:

    Jabber服务器:192.168.1.12,安装Openfire,域为home1

    Jabber用户客户端:192.168.1.10,安装Spark客户端,Jabber用户为chuanliang。

    Jabber联系人客户端:192.168.1.11,安装Spark客户端,Jabber用户为liangchuan

1.3. 测试场景:

测试1:

    Jabber用户chuanliang和Jabber联系人liangchuan被彼此的presence订阅,且允许把彼此加入自己的Roster

测试2

    Jabber联系人liangchuan接受Jabber用户chuanliang的订阅,但是不允许chuanliang加入自己的Roster

测试3

    Jabber联系人liangchuan不接受Jabber用户chuanliang的订阅,同时不允许chuanliang加入自己的Roster

以测试用例“测试1”说明一下测试过程:

1、 chuanliang@home1在192.168.1.10客户端上新增联系人liangchuan@home1

2、 liangchuan@home1在192.168.1.11客户端上“准许chuanliang@home1新增liangchuan@home1到chuanlian的联系人名单中”,同时”Add user to liangchuan’s  roster”

clip_image002

3、 chuanliang@home1在192.168.1.10客户端上“准许liangchuan@home1新增chuanliang@home1到chuanlian的联系人名单中”,同时”Add user to chuanliang’s  roster”

clip_image004

2. 测试1- contact accept subscription and allow add user to it’s roster

2.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端

Ø 192.168.1.10->192.168.1.12

Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster

<iq id="7SJ55-63" type="set">

    <query xmlns="jabber:iq:roster">

        <item jid="liangchuan@home1" name="liangchuan">

            <group>Friends</group>

        </item>

    </query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:

<iq type="set" id="308-51" to="chuanliang@home1/spark">

    <query xmlns="jabber:iq:roster">

        <item jid="liangchuan@home1" name="liangchuan" subscription="none">

            <group>Friends</group>

        </item>

    </query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。

<iq type="result" id="7SJ55-63" to="chuanliang@home1/spark"/>

2.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端

Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)

Ø 192.168.1.10->192.168.1.12

<presence id="7SJ55-64" to="liangchuan@home1" type="subscribe"/>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:

<iq type="set" id="132-52" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" ask="subscribe" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

2.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端

Ø 192.168.1.12->192.168.1.11

Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端

<presence id="7SJ55-64" to="liangchuan@home1" type="subscribe" from="chuanliang@home1"/>

Ø 192.168.1.11->192.168.1.12

Jabber联系人客户端发送一个<iq/>包给Jabber服务器,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster:

<iq id="8SAVC-26" type="set">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" name="chuanliang">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.11

Jabber联系人客户端从服务器接收到一个<iq/>包,其type=’result’

<iq type="result" id="8SAVC-26" to="liangchuan@home1/spark"/>

2.4. Jabber联系人客户端发送一个type=’subscribe’的<presence/>的包给用户客户端

此部分请求发生在联系人客户端“准许chuanliang@home1新增liangchuan@home1到chuanlian的联系人名单中”时候同时选择了:“Add user to liangchuan’s  roster”选项。如果没有选择,则无此部分请求。

Ø 192.168.1.11->192.168.1.12

<presence id="8SAVC-27" to="chuanliang@home1" type="subscribe"/>

Ø 192.168.1.12->192.168.1.10

服务器传递请求给Jabber用户端

<presence id="8SAVC-27" to="chuanliang@home1" type="subscribe" from="liangchuan@home1"/>

Ø 192.168.1.12->192.168.1.10

<iq type="set" id="867-55" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="to">

<group>Friends</group>

</item>

</query>

</iq>

2.5. Jabber联系人客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给用户客户端

联系人下一步要做的就是决定是否接受订阅请求。我们假定联系人接受订阅请求

Ø 192.168.1.11->192.168.1.12

联系人的Jabber客户端发送一个type=’subscribed’的<presence/>的包给Jabber用户(通过服务器端)

<presence id="8SAVC-28" to="chuanliang@home1" type="subscribed"/>

Ø 192.168.1.12->192.168.1.10

<presence id="8SAVC-28" to="chuanliang@home1" type="subscribed" from="liangchuan@home1"/>

<presence id="8SAVC-6" from="liangchuan@home1/spark" to="chuanliang@home1/spark">

<status/>

<priority>1</priority>

</presence>

Ø 192.168.1.12->192.168.1.11

联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”

<iq type="set" id="14-54" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" name="chuanliang" ask="subscribe" subscription="from">

<group>Friends</group>

</item>

</query>

</iq>

2.6. Jabber用户客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给联系人客户端

Ø 192.168.1.10->192.168.1.12

<presence id="7SJ55-65" to="liangchuan@home1" type="subscribed"/>

Ø 192.168.1.12->192.168.1.10

<iq type="set" id="382-56" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="both">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.11

<iq type="set" id="697-57" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" name="chuanliang" subscription="both">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.11

<presence id="7SJ55-65" to="liangchuan@home1" type="subscribed" from="chuanliang@home1"/>

<presence id="7SJ55-51" from="chuanliang@home1/spark" to="liangchuan@home1/spark">

<status/>

<priority>1</priority>

</presence>

3. 测试2- contact accept subscribption and not allow add user to it’s roster

3.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端

Ø 192.168.1.10->192.168.1.12

Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster

<iq id="xHk99-51" type="set">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:

<iq type="set" id="133-130" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。

<iq type="result" id="xHk99-51" to="chuanliang@home1/spark"/>

3.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端

Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)

Ø 192.168.1.10->192.168.1.12

<presence id="xHk99-52" to="liangchuan@home1" type="subscribe"></presence>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:

<iq type="set" id="35-132" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" ask="subscribe" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

3.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端

Ø 192.168.1.12->192.168.1.11

Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端

<presence id="xHk99-52" to="liangchuan@home1" type="subscribe" from="chuanliang@home1"/>

3.4. Jabber联系人客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给用户客户端

联系人下一步要做的就是决定是否接受订阅请求。我们这里联系人接受订阅请求,但是取消”Add user to chuanliang’s  roster”操作。

Ø 192.168.1.11->192.168.1.12

联系人的Jabber客户端发送一个type=’subscribed’的<presence/>的包给Jabber用户(通过服务器端)

<presence id="8SAVC-90" to="chuanliang@home1" type="subscribed"></presence>

Ø 192.168.1.12->192.168.1.10

<presence id="8SAVC-90" to="chuanliang@home1" type="subscribed" from="liangchuan@home1"/>

<presence id="8SAVC-30" from="liangchuan@home1/spark" to="chuanliang@home1/spark">

<status/>

<priority>1</priority>

</presence>

Ø 192.168.1.12->192.168.1.11

联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”

<iq type="set" id="585-135" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" subscription="from"/>

</query>

</iq>

4. 测试3- contact not accept subscription and  not allow add user to it’s roster

4.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端

Ø 192.168.1.10->192.168.1.12

Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster

<iq id="n7NDl-39" type="set">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:

<iq type="set" id="321-250" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。

<iq type="result" id="n7NDl-39" to="chuanliang@home1/spark"/>

4.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端

Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)

Ø 192.168.1.10->192.168.1.12

<presence id="n7NDl-40" to="liangchuan@home1" type="subscribe"/>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:

<iq type="set" id="942-252" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" ask="subscribe" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

4.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端

Ø 192.168.1.12->192.168.1.11

Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端

<presence id="n7NDl-40" to="liangchuan@home1" type="subscribe" from="chuanliang@home1"/>

4.4. Jabber联系人客户端接收订阅请求,发送一个type=’ unsubscribe’的<presence/>的包给用户客户端

联系人下一步要做的就是决定是否接受订阅请求。我们这里联系人接受订阅请求,但是取消”Add user to chuanliang’s  roster”操作。

Ø 192.168.1.11->192.168.1.12

联系人的Jabber客户端发送一个type=’ unsubscribe的<presence/>的包给Jabber用户(通过服务器端)

<presence id="8SAVC-116" to="chuanliang@home1" type="unsubscribe"/>

Ø 192.168.1.12->192.168.1.10

<presence id="8SAVC-116" to="chuanliang@home1" type="unsubscribe" from="liangchuan@home1"/>

Ø 192.168.1.12->192.168.1.11

联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“remove”

<iq type="set" id="190-258" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" subscription="remove"/>

</query>

</iq>

4.5. Jabber用户客户端发送取消订阅请求,发送一个subscription =’ remove’的<iq/>的包给服务器端

Ø 192.168.1.10->192.168.1.12

用户的Jabber客户端发送一个subscription="remove"的包给服务器,取消订阅

<iq id="n7NDl-41" type="set">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="remove" ask="subscribe">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

<iq type="set" id="872-256" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" subscription="remove"/>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

<iq type="result" id="n7NDl-41" to="chuanliang@home1/spark"/>

5. 参考文档

http://www.xmpp.org/extensions/xep-0162.html

http://tools.ietf.org/html/rfc3921

http://www.xmpp.org/extensions/xep-0144.html

 

第三方支付思考-垂直化支付生存之道

     随着国内电子商务市场的高速发展及消费者对在线支付的安全性、便捷性的逐步认可,国内电子支付市场正如火如荼。从1998年第一家第三方支付公司诞生,到2008年,中国的第三方支付已经走进第10个年头。目前,国内第三方支付公司已经有几十家。大家都看好第三方支付的前景,都相信第三方支付会有辉煌的未来。只是在盈利模式、商业模式上目前阶段大部分的第三方支付公司都处于“摸着石头过河”阶段,尚未摆脱叫好不叫座的局面。

    由于做电信增值业务及无线互联网,也在搭建自己的支付平台,因此从自己角度谈谈对支付系统的一些理解,不尽之处敬请拍砖。

    从长远规划来说,我们是希望能够搭建一个独立、具有影响力的第三方支付平台,为分销平台、电子商务平台、通用积分平台、手机支付、增值业务等提供一体化、多渠道的支付工具。但从目前来说,考虑到规避政策风险及定位区隔竞争对手的需要,在近期及中期我们在支付领域最大的核心竞争力还是在电信增值服务领域(包括快充、慢充、广电充值、数字点卡等),因此建议先聚焦在与电信增值业务相关的领域上。

    1、政策风险

    目前国家对于清结算及支付的管理在逐步收紧,已经颁布了《支付清算组织管理办法》、《电子支付指引(第二号)》几个指引性文件,在《支付清算组织管理办法》中明确要求从事清结算支付企业的的注册资金必须1个亿以上,只是由于电子支付牌照的发放一直悬而未决,因此目前政策尚未正式实施,但随着电子支付牌照的发放后,国家对直接第三方支付的管理肯定会收紧。而且银行对虚拟货币监管也在逐步加强,据说好像央行内部好像也在酝酿在年底颁布对从事通用积分资质的监管政策。因此在政策形式尚不明朗的情况下,还是聚焦在垂直领域。

    2、利润

    目前国内诸如支付宝、银联支付、财付通、快钱、易宝等第三方支付系统本身的利润率并不高,单纯依靠交易手续费本身并不足以支撑第三方支付平台的运营,这些企业主要的盈利点还是聚焦在一些关键性行业(尽管大家都做得大而全),例如支付宝依赖其taobao交易中的资金沉淀、银联支付依赖垄断性的基金,财付通依托QQ的虚拟货币体系、快钱和易宝主要还是在慢充及诸如电子机票等一些垂直型行业业务

    3、竞争

    对于初创性的企业而言,最大的挑战不是市场机会的多寡,而是能否忍受住各种机会的诱惑。如果没有专注,什么都想做,那实际上什么都做不成,必须聚焦在自己上场的事情上。毕竟,看见机会与把握机会是两码事,机会只垂青那些做好准备和有能力把握的人。对于初创性企业,可以调配的资源相对有限,必须集中优势兵力打歼灭战才能够生存下来。

    初期支付系统的定位我觉得可以定位于:

    一体化的电信增值业务垂直支付平台

    在电信增值业务这样的垂直支付领域上,随着电信重组及3G时代的到来,在此领域我觉得机会还是蛮大的。

1、一体化的电信增值业务垂直支付平台

    对于大部分的CP/SP而言,电信运营商最大的价值是其收费通道,而在产品、用户、渠道上电信运营商基本上都没有CP/SP帮助拓展,必须CP/SP自己搞定,因此如果能够建立相对中立的电信增值业务垂直支付平台,帮助CP/SP建立多渠道(线上支付、线下实体店面)、多手段(手机、网银、电话、短信、第三方支付、数字点卡)、一体化(移动、联通、电信、广电支付一体化)、更优质、更便捷的支付通道,则必然收到广大CP/SP的欢迎,同时可以提升集团自身的产业链整合能力。电信重组后,与移动、联通、电信、广电运营商的增值业务支付通道及支付接口肯定成为各CP/SP最大的心病,对于大部分的CP/SP而言其实更关注的是业务本身的创新和竞争,大部分CP/SP并没有太多的能力和资源去搞定每一家运营商接口。这一点与电子商务企业需要依赖第三方的在线支付系统比较类似(尽管理论上每一家企业都可以直接与银行去谈接口)。

2、 垂直数字点卡的B2B平台

    在点卡业务上我觉得还是有很大机会,这一点像骏网、天下加油站、云网、卡易售这样的B2B平台的成功可以说明这个市场容量还是很大的,在竞争上,我们也可以区隔定位在:“垂直的电信数字点卡的B2B平台”。像骏网、天下加油站这样的点卡联盟擅长在游戏点卡方面,而在电信增值业务相关的并没有一家聚焦在此领域。

3、手机支付问题

    手机支付肯定具有辉煌的前景,想一想:只需要带一个手机就可以完成所有买卖的支付,这样的场景是多么的激动人心啊。但手机支付目前政策形式比第三方支付牌照更不明朗,包括移动及联通也因政策上的风险问题而局限在小额的电信支付的垂直领域上。因此在策略上只能采取边走边看策略,不建议投入太多的资源。

 

电信重组时代的增值业务思考

    电信重组后,由于运营商间竞争的加剧及对客户提供差异化服务的需求,3G时代数据业务、增值业务及互联网相关业务成为运营商的下一个奶酪,面临巨大的市场机会,开始思考电信重组时代下与各运营商的合作策略及增值业务的市场机会。

1、未来增值业务运营模式展望

2008-7-12 18-12-01

摘自《电信业转型与增值业务发展分析》

2、运营商合作策略

2.1、移动合作策略:

移动增值业务

    针对移动的产品规划,好好琢磨一下我们的机会所在。

    空中充值这一块可以强化对客户充值行为的分析,这样可以更好为客户推荐适合的套餐产品(尤其是其他运营商的,帮助其转网)。

    移动开放了手机网游的接口,给手机网游的研发商和运营商提供了优质的宣传渠道和收费模式,此举必定能够大力推动手机网络游戏行业的快速发展。但正如其他互联网产品一样,手机网游运营平台的运营涉及虚拟货币、社区、联盟推广互联网的典型玩法,这这并不是移动这样的运营商所擅长的,因此需要专业化的运营团队,这也是我们的价值所在。

2.2、电信合作策略:

    我觉得电信是重组的最大受益者,同时电信人员本身的素质还是挺高,因此电信pk移动的竞争力还是在的,在电信的移动业务拓展期我们与其合作的空间及利润上可能比移动更高。另外电信是3个运营商里唯一没有移动增值业务平台的(实际上只有固网的增值业务,CDMA的增值业务应该留在联通),这一块我们也有很大机会。

2.3、广电合作策略:

    在所有的运营商,广电网络在各个地方各自为政,而且其核心的BOSS系统做得很差,但由于是核心系统这一块我们机会不大。广电自己类似移动MISC的增值业务的运营平台也在加紧建设中,但广电在这一块并没有任何思路,这一块广电我们机会还是较多的。我们可以尝试利用eSales系统帮助其建设增值业务的运营平台,而不单纯局限在帮助其收费上。

    另外由于数字电视的普及推广,基于数字电视的增值业务逐渐在成熟中,我们可以尝试利用内容整合的优势,在广电的一些频道中承包一些栏目来独自运营或合作运营。

    由于在手机电视上,广电有比其他运营商的牌照优势,因此在客户端研发及运营上,我们可以与其探讨合作的可能性。

3、重点业务思考概述  

3.1、带号转网

     工业和信息化部正在酝酿带号转网的方案,电信重组后,由于频段资源稀缺及扶植电信、联通这样的相对弱小运营商不对称竞争的需要,带号转网的步伐应该会加快,这一点可以作为一个专题研究一下。

    那些拥有客户消费资料及终端销售渠道的代理商应该可以成为带号转网最大的机会是那些用于终端用户

3.2、增值业务销售通路

    电信重组后,各运营商对渠道、终端、客户、内容产品的争夺肯定更为激烈,而3G核心的竞争还是在于内容本身。在目前无线互联网及电信增值业务市场中,众多的内容提供商、服务提供商、软件开发厂商以及众多初创性互联网企业具有各种内容丰富的产品,但由于终端渠道、政策上、技术上的限制,这些产品没有好的销售通路和销售管理平台。对于我们这样拥有众多具有良好合作关系的通信连锁企业的传统销售终端渠道,“渠道为王”。通过无线增值内容eSales分销平台的建设,整合海量无线互联网内容资源,充分整合和利用合作伙伴传统连锁渠道的优势,为合作伙伴及终端销售的店员提供增值内容的销售服务平台;为CP、SP及无线互联网提供商提供内容分发、内容计费渠道通路及运营平台,协助其业务拓展;为广告主提供精准式的广告投放手段。通过手机连锁传播、手机无线互联网传输、互联网和其他线下传播方式有机结合,直接为消费者提供手机增值服务的平台架构。

3.3、电信增值业务垂直支付平台

   对于大部分的CP/SP而言,电信运营商最大的价值是其收费通道,而在产品、用户、渠道上电信运营商基本上都没有CP/SP帮助拓展,必须CP/SP自己搞定,因此如果能够建立相对中立的电信增值业务垂直支付平台,帮助CP/SP建立多渠道(线上支付、线下实体店面)、多手段(手机、网银、电话、短信、第三方支付、数字点卡)、一体化(移动、联通、电信、广电支付一体化)、更优质、更便捷的支付通道,则必然收到广大CP/SP的欢迎,同时可以提升集团自身的产业链整合能力。

3.4、三网合一及IPTV

    现在看来,大家这几年对三网合一及IPTV发展进度都估计太乐观,整个进度比原来大家预想的慢多了,政策形式的不明朗导致目前整个仍然处于培育期,到正式的商用运营尚有很长的路程需要走,只能静观其变。

3.5、3G

    继续思考中…

 

手机电子商务杂思1-没有夕阳产业,只有夕阳思维

    近年来,随着国美、苏宁这样的家电连锁卖场在手机零售市场上话语权的不断增强,以及移动、联通等运营商定制手机的日益强势;还有诸如电脑卖场等销售渠道加入导致手机销售渠道的多样化和扁平化,专业手机销售连锁企业感受到了重重压力。“扩大规模”成为这些企业的第一选择,但店铺租金、押金越来越高,人员工资上涨等因素的影响,传统手机卖场的利润越来越薄,同时出现了今年以来各连锁企业销售额下滑30%的现状。同样的事情发生在手机制造企业,moto的衰败以及国内夏新、波导这些国内曾经的明星企业的陨落更让人对手机行业生存压力无限感叹:手机行业的冬天已经来临、手机连锁已是夕阳产业。

    其实手机连锁企业的利润率相比传统家电连锁企业、中关村那些靠组装电脑企业为生的企业相比较,其利润率还是高多了,但是其企业管理能力、从业人员的素质、对供应链的管理能力、客户关系管理、对IT信息系统、互联网的使用却是极其的低下,只是近10多年行业的高速发展所带来的机遇让所有的企业认为是自己企业管理的胜利、战略决策的胜利,所有的问题都被深深掩埋在利润下。

    Apple iphone的无限风光,天宇及山寨机的异军突起说明这个市场一样存在无限的市场机会,对于后来者仍然可以通过技术创新、营销的创新、管理的创新、商业模式的创新来超越先入者。   

    相比于Apple对整个产业链的掌控能力及IPHONE的技术创新而言,天宇及山寨机的成功实质上是营销手段的成功,而非技术的创新,其成功秉承了中国制造成功的特质:更低(更低的价格)、更快(更加敏锐的市场需求更觉和制造速度)、更强(更为强大的功能)。尽管这些企业能否长青尚待考证(相信很多企业仍然只是昙花一现),但山寨机在残酷的市场竞争中所表现出的对市场需求的敏锐把握和满足这种需求的反映速度及创新能力(尽管这样的创新只是低层次的),已经足以让人深思。

    在竞争压力下,几乎所有的手机连锁企业都开始通过进军电子商务,以谋求突围谋求。但难道只是组建一个团队,然后搭建一个网站就能够完成传统连锁企业向电子商务的转型吗?思维不进行转变,那连锁企业所面临的困境不可能得到解决。

    只有一个一流的思维与国际接轨的思维,才能创造一流的企业。这个世界上有真正的夕阳产业吗?当然是没有,我们没有夕阳产业,只有夕阳思考。–郎咸平

 

下一页 »