HBase:为客户行为生成搜索点击事件统计信息

在本文中,我们将探索HBase来存储客户搜索点击事件数据,并利用其基于搜索查询字符串和构面过滤器点击来获取客户行为信息。 我们将介绍如何使用MiniHBaseCluster,HBase Schema设计,使用HBaseSink与Flume集成以存储JSON数据。



在之前的文章的基础上,

  • 客户产品搜索使用大数据进行点击分析 ,
  • Flume:使用Apache Flume收集客户产品搜索点击数据 ,
  • Hive:使用Apache Hive查询客户最喜欢的搜索查询和产品视图计数 ,
  • ElasticSearch-Hadoop:将产品视图计数和从Hadoop到ElasticSearch的客户顶部搜索查询建立索引 ,
  • Oozie:为Hive分区和ElasticSearch索引安排协调器/捆绑作业 ,
  • Spark:大数据的实时分析,可用于热门搜索查询和热门产品视图

我们已经探索了将搜索点击事件数据存储在Hadoop中并使用不同的技术对其进行查询。 在这里,我们将使用HBase实现相同的目的:

  • HBase小型集群设置
  • 使用Spring Data的HBase模板
  • HBase模式设计
  • 使用HBaseSink进行Flume集成
  • HBaseJsonSerializer序列化json数据
  • 查询过去一个小时的前10个搜索查询字符串
  • 查询过去一个小时的前10个搜索方面过滤器
  • 获取最近30天内客户的最近搜索查询字符串

searchanalytics-hbase-flume

HBase的

HBase “是Hadoop数据库,一个分布式,可扩展的大数据存储。”

HBaseMiniCluster / MiniZookeperCluster

要设置和启动小型集群,请检查HBaseServiceImpl.java

...miniZooKeeperCluster = new MiniZooKeeperCluster();miniZooKeeperCluster.setDefaultClientPort(10235);miniZooKeeperCluster.startup(new File("taget/zookeper/dfscluster_" + UUID.randomUUID().toString()).getAbsoluteFile());...Configuration config = HBaseConfiguration.create();config.set("hbase.tmp.dir", new File("target/hbasetom").getAbsolutePath());config.set("hbase.master.port", "44335");config.set("hbase.master.info.port", "44345");config.set("hbase.regionserver.port", "44435");config.set("hbase.regionserver.info.port", "44445");config.set("hbase.master.distributed.log.replay", "false");config.set("hbase.cluster.distributed", "false");config.set("hbase.master.distributed.log.splitting", "false");config.set("hbase.zookeeper.property.clientPort", "10235");config.set("zookeeper.znode.parent", "/hbase");miniHBaseCluster = new MiniHBaseCluster(config, 1);miniHBaseCluster.startMaster();...

MiniZookeeprCluster在客户端端口10235上启动,所有客户端连接都将在此端口上。 确保将hbase服务器端口配置为不与其他本地hbase服务器冲突。 在这里,我们仅在测试案例中启动一台hbase区域服务器。

使用Spring数据的HBase模板

我们将使用Spring hbase模板连接到HBase集群:

<hdp:hbase-configuration id="hbaseConfiguration" configuration-ref="hadoopConfiguration" stop-proxy="false" delete-connection="false" zk-quorum="localhost" zk-port="10235"></hdp:hbase-configuration><bean id="hbaseTemplate" class="org.springframework.data.hadoop.hbase.HBaseTemplate" p:configuration-ref="hbaseConfiguration" />

HBase表架构设计

我们具有以下格式的搜索点击事件JSON数据,

{"eventid":"24-1399386809805-629e9b5f-ff4a-4168-8664-6c8df8214aa7","hostedmachinename":"192.168.182.1330","pageurl":"http://blahblah:/5&quot ;,"customerid":24,"sessionid":"648a011d-570e-48ef-bccc-84129c9fa400","querystring":null,"sortorder":"desc","pagenumber":3,"totalhits":28,"hitsshown":7,"createdtimestampinmillis":1399386809805,"clickeddocid":"41","favourite":null,"eventidsuffix":"629e9b5f-ff4a-4168-8664-6c8df8214aa7","filters":[{"code":"searchfacettype_color_level_2","value":"Blue"},{"code":"searchfacettype_age_level_2","value":"12-18 years"}]}

处理数据的一种方法是将其直接存储在一个列族和json列下。 这样扫描json数据将变得不那么容易和灵活。 另一种选择是将其存储在一个列族下,但具有不同的列。 但是将过滤器数据存储在单列中将很难进行扫描。 下面的混合方法是将其划分为多个列族,并动态生成用于过滤器数据的列。

转换后的架构为:

{
"client:eventid" => "24-1399386809805-629e9b5f-ff4a-4168-8664-6c8df8214aa7",
"client:eventidsuffix" => "629e9b5f-ff4a-4168-8664-6c8df8214aa7",
"client:hostedmachinename" => "192.168.182.1330",
"client:pageurl" => "http://blahblah:/5",
"client:createdtimestampinmillis" => 1399386809805,
"client:cutomerid" => 24,
"client:sessionid" => "648a011d-570e-48ef-bccc-84129c9fa400",
"search:querystring" => null,
"search:sortorder" => desc,
"search:pagenumber" => 3,
"search:totalhits" => 28,
"search:hitsshown" => 7,
"search:clickeddocid" => "41",
"search:favourite" => null,
"filters:searchfacettype_color_level_2" => "Blue",
"filters:searchfacettype_age_level_2" => "12-18 years"
}

将创建以下三列系列:

  • client :存储事件的客户和客户数据特定信息。
  • search :与查询字符串和分页信息有关的搜索信息存储在此处。
  • 过滤器:为了将来支持更多构面等,并更灵活地扫描数据,将基于构面名称/代码动态创建列名称,并将列值存储为构面过滤器值。

要创建hbase表,

...TableName name = TableName.valueOf("searchclicks");HTableDescriptor desc = new HTableDescriptor(name);desc.addFamily(new HColumnDescriptor(HBaseJsonEventSerializer.COLUMFAMILY_CLIENT_BYTES));desc.addFamily(new HColumnDescriptor(HBaseJsonEventSerializer.COLUMFAMILY_SEARCH_BYTES));desc.addFamily(new HColumnDescriptor(HBaseJsonEventSerializer.COLUMFAMILY_FILTERS_BYTES));try {HBaseAdmin hBaseAdmin = new HBaseAdmin(miniHBaseCluster.getConf());hBaseAdmin.createTable(desc);hBaseAdmin.close();} catch (IOException e) {throw new RuntimeException(e);}...

在创建表时已添加了相关列族,以支持新的数据结构。 通常,建议尽量减少列族的数量,并牢记如何根据使用情况来构造数据。 根据以上示例,我们将扫描场景保持为:

  • 如果您想根据网站上的总访问量信息来检索客户或客户信息,请扫描客户家庭。
  • 扫描搜索信息以查看最终客户正在寻找哪些免费文本搜索,而导航搜索却无法满足这些需求。 请参阅在哪个页面上单击了相关产品,您是否需要加强应用才能将产品推高。
  • 扫描过滤器系列,以了解导航搜索如何为您工作。 是否为最终客户提供他们想要的产品。 查看更多点击哪些构面过滤器,您是否需要在订购中提高一点以便于客户轻松使用。
  • 应避免在家庭之间进行扫描,而应使用行键设计来获得特定的客户信息。

行键设计信息

在我们的例子中,行键设计基于customerId-timestamp -randomuuid 。 由于所有列族的行键都相同,因此我们可以使用“前缀过滤器”对仅与特定客户相关的行进行过滤。

final String eventId = customerId + "-" +  searchQueryInstruction.getCreatedTimeStampInMillis() + "-" + searchQueryInstruction.getEventIdSuffix();
...
byte[] rowKey = searchQueryInstruction.getEventId().getBytes(CHARSET_DEFAULT);
...
# 24-1399386809805-629e9b5f-ff4a-4168-8664-6c8df8214aa7

这里的每个列族都有相同的行键,并且您可以使用前缀过滤器仅扫描特定客户的行。

水槽整合

HBaseSink用于将搜索事件数据直接存储到HBase。 检查详细信息FlumeHBaseSinkServiceImpl.java

...channel = new MemoryChannel();Map<String, String> channelParamters = new HashMap<>();channelParamters.put("capacity", "100000");channelParamters.put("transactionCapacity", "1000");Context channelContext = new Context(channelParamters);Configurables.configure(channel, channelContext);channel.setName("HBaseSinkChannel-" + UUID.randomUUID());sink = new HBaseSink();sink.setName("HBaseSink-" + UUID.randomUUID());Map<String, String> paramters = new HashMap<>();paramters.put(HBaseSinkConfigurationConstants.CONFIG_TABLE, "searchclicks");paramters.put(HBaseSinkConfigurationConstants.CONFIG_COLUMN_FAMILY, new String(HBaseJsonEventSerializer.COLUMFAMILY_CLIENT_BYTES));paramters.put(HBaseSinkConfigurationConstants.CONFIG_BATCHSIZE, "1000");paramters.put(HBaseSinkConfigurationConstants.CONFIG_SERIALIZER, HBaseJsonEventSerializer.class.getName());Context sinkContext = new Context(paramters);sink.configure(sinkContext);sink.setChannel(channel);sink.start();channel.start();...

客户端列系列仅用于HBaseSink的验证。

HBaseJsonEventSerializer

创建自定义序列化器以存储JSON数据:

public class HBaseJsonEventSerializer implements HBaseEventSerializer {public static final byte[] COLUMFAMILY_CLIENT_BYTES = "client".getBytes();public static final byte[] COLUMFAMILY_SEARCH_BYTES = "search".getBytes();public static final byte[] COLUMFAMILY_FILTERS_BYTES = "filters".getBytes();...byte[] rowKey = searchQueryInstruction.getEventId().getBytes(CHARSET_DEFAULT);Put put = new Put(rowKey);// Client Inforput.add(COLUMFAMILY_CLIENT_BYTES, "eventid".getBytes(), searchQueryInstruction.getEventId().getBytes());...if (searchQueryInstruction.getFacetFilters() != null) {for (SearchQueryInstruction.FacetFilter filter : searchQueryInstruction.getFacetFilters()) {put.add(COLUMFAMILY_FILTERS_BYTES, filter.getCode().getBytes(),filter.getValue().getBytes());}}...

检查更多详细信息, HBaseJsonEventSerializer.java

事件主体从Json转换为Java bean,并进一步处理数据以在相关的列系列中进行序列化。

查询原始单元格数据

要查询原始单元格数据:

...Scan scan = new Scan();scan.addFamily(HBaseJsonEventSerializer.COLUMFAMILY_CLIENT_BYTES);scan.addFamily(HBaseJsonEventSerializer.COLUMFAMILY_SEARCH_BYTES);scan.addFamily(HBaseJsonEventSerializer.COLUMFAMILY_FILTERS_BYTES);List<String> rows = hbaseTemplate.find("searchclicks", scan,new RowMapper<String>() {@Overridepublic String mapRow(Result result, int rowNum) throws Exception {return Arrays.toString(result.rawCells());}});for (String row : rows) {LOG.debug("searchclicks table content, Table returned row: {}", row);}

检查HBaseServiceImpl.java以获得详细信息。

数据以以下格式存储在hbase中:

searchclicks table content, Table returned row: [84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/client:createdtimestampinmillis/1404832918166/Put/vlen=13/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/client:customerid/1404832918166/Put/vlen=2/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/client:eventid/1404832918166/Put/vlen=53/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/client:hostedmachinename/1404832918166/Put/vlen=16/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/client:pageurl/1404832918166/Put/vlen=19/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/client:sessionid/1404832918166/Put/vlen=36/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/filters:searchfacettype_product_type_level_2/1404832918166/Put/vlen=7/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/search:hitsshown/1404832918166/Put/vlen=2/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/search:pagenumber/1404832918166/Put/vlen=1/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/search:querystring/1404832918166/Put/vlen=13/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/search:sortorder/1404832918166/Put/vlen=3/mvcc=0, 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923/search:totalhits/1404832918166/Put/vlen=2/mvcc=0]

查询过去一个小时的前10个搜索查询字符串

要仅查询搜索字符串,我们只需要搜索列族。 要在时间范围内进行扫描,我们可以使用client列系列创建的timestampinmillis列,但这将是扩展扫描。

...Scan scan = new Scan();scan.addColumn(HBaseJsonEventSerializer.COLUMFAMILY_CLIENT_BYTES, Bytes.toBytes("createdtimestampinmillis"));scan.addColumn(HBaseJsonEventSerializer.COLUMFAMILY_SEARCH_BYTES, Bytes.toBytes("querystring"));List<String> rows = hbaseTemplate.find("searchclicks", scan,new RowMapper<String>() {@Overridepublic String mapRow(Result result, int rowNum) throws Exception {String createdtimestampinmillis = new String(result.getValue(HBaseJsonEventSerializer.COLUMFAMILY_CLIENT_BYTES, Bytes.toBytes("createdtimestampinmillis")));byte[] value = result.getValue(HBaseJsonEventSerializer.COLUMFAMILY_SEARCH_BYTES, Bytes.toBytes("querystring"));String querystring = null;if (value != null) {querystring = new String(value);}if (new DateTime(Long.valueOf(createdtimestampinmillis)).plusHours(1).compareTo(new DateTime()) == 1 && querystring != null) {return querystring;}return null;}});...//sort the keys, based on counts collection of the query strings.List<String> sortedKeys = Ordering.natural().onResultOf(Functions.forMap(counts)).immutableSortedCopy(counts.keySet());...

查询过去一个小时的前10个搜索方面过滤器

基于动态列创建,您可以扫描数据以返回点击次数最高的构面过滤器。

动态列将基于您的方面代码,这些代码可以是以下任意一种:

#searchfacettype_age_level_1#searchfacettype_color_level_2#searchfacettype_brand_level_2#searchfacettype_age_level_2for (String facetField : SearchFacetName.categoryFacetFields) {scan.addColumn(HBaseJsonEventSerializer.COLUMFAMILY_FILTERS_BYTES, Bytes.toBytes(facetField));}

检索到:

...hbaseTemplate.find("searchclicks", scan, new RowMapper<String>() {@Overridepublic String mapRow(Result result, int rowNum) throws Exception {for (String facetField : SearchFacetName.categoryFacetFields) {byte[] value = result.getValue(HBaseJsonEventSerializer.COLUMFAMILY_FILTERS_BYTES, Bytes.toBytes(facetField));if (value != null) {String facetValue = new String(value);List<String> list = columnData.get(facetField);if (list == null) {list = new ArrayList<>();list.add(facetValue);columnData.put(facetField, list);} else {list.add(facetValue);}}}return null;}});...

您将获得所有构面的完整列表,可以进一步处理数据以计算顶面并对其进行排序。 有关完整的详细信息,请检查HBaseServiceImpl.findTopTenSearchFiltersForLastAnHour

获取客户的最近搜索查询字符串

如果需要检查客户当前正在寻找什么,我们可以在“客户”和“搜索”之间的两个列族之间创建扫描。 或者,另一种方式是设计行键,以便为您提供相关信息。 在我们的例子中,行键设计基于CustomerId_timestamp _randomuuid。 由于所有列族的行键都相同,因此我们可以使用“前缀过滤器”对仅与特定客户相关的行进行过滤。

final String eventId = customerId + "-" +  searchQueryInstruction.getCreatedTimeStampInMillis() + "-" + searchQueryInstruction.getEventIdSuffix();
...
byte[] rowKey = searchQueryInstruction.getEventId().getBytes(CHARSET_DEFAULT);
...
# 84-1404832902498-7965306a-d256-4ddb-b7a8-fd19cdb99923

要扫描特定客户的数据,

...Scan scan = new Scan();scan.addColumn(HBaseJsonEventSerializer.COLUMFAMILY_SEARCH_BYTES, Bytes.toBytes("customerid"));Filter filter = new PrefixFilter(Bytes.toBytes(customerId + "-"));scan.setFilter(filter);...

有关详细信息,请检查HBaseServiceImpl.getAllSearchQueryStringsByCustomerInLastOneMonth

希望这可以帮助您入门HBase模式设计和处理数据。

翻译自: https://www.javacodegeeks.com/2014/07/hbase-generating-search-click-events-statistics-for-customer-behavior.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362753.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

控制HTML Input只能输入数字和小数点

转&#xff1a;https://www.cnblogs.com/esion/p/3342866.html 本文介绍三种控制在中只允许输入数字和小数点的方案。 方案1&#xff1a;通过JavaScript代码实现。 JavaScript代码如下&#xff1a; function checkNum(obj) {//检查是否是非数字值if (isNaN(obj.value)) {obj…

2019-05-14 Sonar部署

1.下载软件地址&#xff1a;https://www.sonarqube.org/#downloads 官方文档&#xff1a;https://docs.sonarqube.org/display/SCAN/AnalyzingwithSonarQubeScannerforAnt 2.LTS Release不是最新但是是稳定的版本长久支持&#xff1b;Latest Realease是最新版本不稳定&#xff…

WildFly 8.1.0.Final上的SwitchYard 2.0.0.Alpha1入门

最近&#xff0c;我一直在关注一些热门的RedHat技术&#xff0c;在其中很多有趣的部分中&#xff0c;我找到了SwitchYard 。 过去&#xff0c;对于所有人都围绕SOA和面向服务的体系结构不屑一顾&#xff0c;这对我来说一直很奇怪&#xff0c;作为Java EE开发人员。 过去&#…

void main()是错误的

USE_NET新闻组一直苦恼于一个问题的讨论&#xff0c;我们能否用void作为一个main的返回类型&#xff0c;ANSI标准说不能&#xff0c;然而&#xff0c;大量的关于C的启蒙书中的例子都使用了void main (void)&#xff0c;这让许多人感觉不知该如何是好。 当有人问为什么使用void是…

zTree 优秀的jquery树插件

zTree 优秀的jquery树插件,文档详细&#xff0c;渲染快 使用方法&#xff1a; 1、引用zTree的js和css文件   <link href"~/Content/zTree_v3/css/zTreeStyle/zTreeStyle.css" rel"stylesheet" /><script src"~/Content/zTree_v3/js/jque…

执行点击事件,第一次点击后,一切正常,第二次点击,执行两次,以此类推

今天执行点击事件的时候&#xff0c;第一个点击正常&#xff0c;第二次点击接口调用了两次&#xff0c;第三次点击接口调用了3次。。。。我还以为是我的push数组写错了&#xff0c;后来发现是因为jq绑定一个按钮click事件的问题。 1.在点击事件上面添加了一行代码**$(’#btn’)…

牛客 2B 树 (组合计数)

传送门 大意: 给定n节点树, 求划分为不超过$k$个连通块的方案数. n,k<300. 核心观察是每个连通块深度最低的点固定以后染色方案就固定了. 所以答案为$\sum\limits_{i1}^k\binom{k}{i}i!\binom{n-1}{i-1}$ 转载于:https://www.cnblogs.com/uid001/p/10864775.html

Java中的42行代码中的URL缩短服务— Java(?!)Spring Boot + Redis

显然&#xff0c;编写URL缩短服务是新的“ Hello&#xff0c;world&#xff01; ”在IoT /微服务/时代的世界中。 一切始于在45行Scala中的URL缩短服务 -整洁的Scala&#xff0c;以Spray和Redis进行调味以进行存储。 随后&#xff0c; 在35行Clojure中使用了url缩短服务&#x…

poj 3256(DFS)

http://acm.pku.edu.cn/JudgeOnline/problem?id3256 题意&#xff1a;有k头牛&#xff0c;n个牧场&#xff0c;m条路&#xff08;每条路相连两个牧场且单向&#xff09;&#xff0c;求全部牛都能到达的牧场有几个。 分析&#xff1a;用DFS&#xff0c;从每头牛所在牧场开始&am…

jquery常用表单操作

//js将表单序列化成对象$.fn.serializeObject function () {var $els $(this).find("[name]");var formData {};var len $els.length;for (var i 0; i < len; i ) {var $item $($els[i]);var name $item.attr("name");var type $item.attr(&qu…

Android 小項目之---Iphone拖动图片特效 (附源码)

曾经被Iphone用手指在屏幕上滑来滑去拖动图片的操作方式吸引吗&#xff1f;在Android里头&#xff0c;这并不是什么难事。 所需要的技术点如下&#xff1a;Android.content.Context 、Android.widget.BaseAdapter、Android.widget.ImageView等通常会用在设计相册、 图片类型的选…

jq绑定的事件不生效

不知道什么原因&#xff0c;写了一段代码之后&#xff0c;绑定的所有的jq事件都不生效了。后来百度了一下&#xff0c;这里列出一种方法。 转载&#xff1a;https://www.jb51.net/article/46666.html $("#ceshisub").bind("click",function(){ var a1; …

Python笔记_第三篇_面向对象_6.继承(单继承和多继承)

1. 概念解释&#xff1a; 继承&#xff1a;有两个类&#xff1a;A类和B类。那么A类就拥有了B类中的属性和方法。 * 例如&#xff1a;Object&#xff1a;是所有类的父亲&#xff0c;还可以成为基类或者超类&#xff08;super()&#xff09; * 继承者为子类&#xff0c;被继承者成…

文本内容之间的关键词提取和相似度计算

背景 Web应用程序变得越来越智能。 从网站上使用服务的日子已经一去不复返了&#xff0c;用户不得不填写一个巨大的表格。 假设您有一个适合书迷的网站。 在Web 2.0之前&#xff0c;此类网站曾经以诸如年龄&#xff0c;阅读书籍&#xff0c;喜欢的书籍类型&#xff0c;语言偏好…

Windows XP SP3支持多用户远程桌面连接

远程桌面连接的确很方便&#xff0c;但是在Windows XP中只支持单一用户的连接&#xff0c;当第二个用户连接时&#xff0c;第一个用户就被迫断开并回到用户登录界面了&#xff0c;这可和多任务的操作系统理念不符啊&#xff0c;或许微软是为了突出Server系统的特点吧&#xff0…

构建用于测试的超大型内存InputStream

由于某种原因&#xff0c;我需要非常大的&#xff0c;甚至可能是无限的InputStream &#xff0c;它会反复地反复返回相同的byte[] 。 这样&#xff0c;我可以通过重复小样本来产生大量的数据流。 在Guava中可以找到类似的功能&#xff1a; Iterable<T> Iterables.cycle(I…

linux 调试小经验

1、查看netlink socket 丢包 cat /proc/net/netlink sk Eth Pid Groups Rmem Wmem Dump Locks Drops Inode c91eda00 0 1172 00000001 0 0 00000000 2 0 27767 c43eee00 0 -4099 00000000 0 0 00000000 2 0 41200 c9266e00 0 1186 00000000 0 0 00000000 2 0 28922 c1af580…

前端打印功能

方法一&#xff1a; html代码&#xff1a; 在要打印的内容上加入&#xff1a;<!--startprint-->和<!--endprint--> js代码&#xff1a; $(.printData).click(function(){bdhtmlwindow.document.body.innerHTML; sprnstr"<!--startprint-->"; …

Vlc支持IE 360 低版本的Google浏览器

VLC 插件代码&#xff1a; <object typeapplication/x-vlc-plugin pluginspage"http://www.videolan.org/" idvlc eventsfalse width"720" height"410"><param namemrl valuertsp://admin:123456******:554/h264/ch1/main/av_stream /&…

同步多线程

同步多线程&#xff08;SMT&#xff09;是一种在一个CPU 的时钟周期内能够执行来自多个线程的指令的硬件多线程技术。本质上&#xff0c;同步多线程是一种将线程级并行处理&#xff08;多CPU&#xff09;转化为指令级并行处理&#xff08;同一CPU&#xff09;的方法。 同步多线…