倒排索引,如斯优雅

背景

 最近看了老大的一篇文章<<使用倒排索引建立本地缓存>>,哎,学到东西了,所以想在这里记录一下。

倒排索引

目录

  • 概念

  • 从百度搜索说起

  • 定向广告投放中倒排索引的应用

概念

首先看一下在百度百科中给出的定义:

倒排索引英语:(Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:"单词词典"和"倒排文件"。  

   倒排索引有两种不同的反向索引形式: 一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表。 一个单词的水平反向索引(或者完全反向索引)又包含每个单词在一个文档中的位置。  

   后者的形式提供了更多的兼容性(比如短语搜索),但是需要更多的时间和空间来创建。  现代搜索引擎的索引都是基于倒排索引。相比“签名文件”、“后缀树”等索引结构,“倒排索引”是实现单词到文档映射关系的最佳实现方式和最有效的索引结构。

嗯,听起来有点复杂。接下来,我用一些通俗易懂的人话来尝试解析一下:

 什么是倒排索引?先不说索引,就倒排俩字就已经让我懵逼了。如果"A-Z"是正排,那么在我的理解中,倒排就是"Z-A"。但是在此处,倒排的意义并非如此。先来看一下正宗的倒排索引的英文翻译,"inverted index"。嗯,不知道是哪位前辈首先给翻译成了"倒排索引",典型的渣渣翻译之一。那么首先我们来了解一下什么是inverted index?就我个人的理解以及结合网上的的一些资料整理出:  

     正排索引:文档 ---> 单词。

  倒排索引:单词 --->文档。

  嗯,接下来来看一个例子看一下是如何创建倒排索引的:

 step1:首先创建一个文档列表:

 step2:创建倒排索引列表:

 step3:如果我们需要查找关键词为"礼物"的文章,那么我们根据倒排索引表就可以得到相应的文档编号集合为:1,2,4。这就是所谓的倒排索引,通过单词查找文档。

  那么我们可以总结出倒排索引建立索引的流程为:

1) 首先把所有的原始数据进行编号,形成文档列表。

2) 把文档数据进行分词,得到很多的词条,以词条为索引。保存包含这些词条的文档的编号信息。

从百度搜索说起

  虽然说百度搜索在搜索的时候展示给我们的很多都是一些竞价广告,但是也是力压了搜狗,360等一批搜索的。在google被qiang了以后,国民使用的最多的还是百度搜索。那么现在就以百度搜索为例子,深入理解一下倒排索引是怎么在搜索中起到关键作用的。

首先我们在百度搜索中输入"精美生日礼物",以后,我们可以看到百度搜索给我们推荐的结果:

我们再进一步查看一下这张图的信息:

  • 观察搜索返回的结果,我们可以明确的知道,百度搜索后台对"生日礼物","精美生日礼物","礼物"等关键词做了飘红处理。

  • 从这张图中,我们可以明显感觉得到,百度对我们输入的"精美生日礼物"做了中文分词处理。可能是切割成了"精美生日礼物","生日礼物","礼物"等几个词,然后再使用这几个词去搜索,最后给我们返回搜索结果。其实从这里我们也可以得到一点启发,由于中文分词不一定是准确的,那么我们在搜索的时候,可以手动分词,也就是关键词之间使用空格进行分割,那么这样搜索出来的结果可能会更加的准确。

  • 文档中的关键词和搜索关键词的匹配程度越高,那么搜索结果的排名也考前,竞价广告除外。

那么百度搜索是如何利用倒排索引的呢?

1) 必定也有一张文档列表。

2) 做了分词处理以后,根据下面的这张表返回搜索结果。那么按照理论来说,含"生日礼物",“礼物”的文档都会返回,也就是会返回编号为1,2,4的文档。

定向广告投放中倒排索引的应用

首先了解一下定向广告投放的含义:

 所谓的定向广告投放,就是根据用户的标签来给她返回适合她口味的广告,以使广告效益最大。

那什么是广告投放的倒排索引呢:

 如果将广告看作是doc,将广告标签看作word,那么通过广告标签找广告的过程就是倒排索引。

我们先来定义我们的数据模型:

表的名称表的含义
unit广告单元表
unit_targeting广告定向信息表

接下来看一下广告定向信息表的一些内容:

   如果我们知道了某个用户是深圳的,我们想给她返回贴了深圳标签的广告,使用倒排索引,即为每个定向选项创建一个单元 id 的列表。该怎么做呢?talk less and show you the code。

step1:定义unit_targeting。

/**

* 广告单元定向信息表

* @author liguo

* @date 2018-9-8

*

*/

public class AdUnitTargeting {



   /**广告单元id**/

   private Long unitId;

   /**广告标签,比如说是年龄,城市,爱好等等**/

   private String  targetType;

   /**定向内容,假如说targetType是“城市”,那么此content可以是"杭州,珠海,深圳"**/

   private String content;





   public Long getUnitId() {

       return unitId;

   }

   public void setUnitId(Long unitId) {

       this.unitId = unitId;

   }

   public String getTargetType() {

       return targetType;

   }

   public void setTargetType(String targetType) {

       this.targetType = targetType;

   }

   public String getContent() {

       return content;

   }

   public void setContent(String content) {

       this.content = content;

   }



}

step2:定义广告单元倒排索引接口。

import java.util.List;

import java.util.Set;



/**

* 广告单元倒排索引接口

* @author liguo

* @date 2018-9-8

*

*/

public interface UnitInvertedIndexer {



   /**

    * 倒排索引

    * @param targetings

    * @return

    */

   public UnitInvertedIndexer buildIndex(List<AdUnitTargeting> targetings);



   /**

    *

    * @param keyword

    * @return

    */

   public Set<Long> search(String keyword);



}

step3:实现广告单元倒排索引接口。

import java.util.HashMap;

import java.util.HashSet;

import java.util.List;

import java.util.Map;

import java.util.Set;

import java.util.StringTokenizer;



/**

* 广告单元倒排索引接口

* @author liguo

* @date 2018-9-8

*

*/

public class UnitInvertedIndexerImpl implements UnitInvertedIndexer {

   private Map<String, Set<Long>> cache = new HashMap<String, Set<Long>>();

   @Override

   public Set<Long> search(String keyword) {

       return cache.get(keyword);

   }

   @Override

   public UnitInvertedIndexer buildIndex(List<AdUnitTargeting> targetings) {

       Map<String, Set<Long>> map = new HashMap<String, Set<Long>>();

       for (AdUnitTargeting targeting : targetings) {

           Set<String> tokens = participle(targeting.getContent());

           if (tokens != null && tokens.size() > 0) {

               for (String token : tokens) {

                   Set<Long> ids = map.get(token);

                   if (ids == null) {

                       ids = new HashSet<Long>();

                       map.put(token, ids);

                   }

                   ids.add(targeting.getUnitId());

               }

           }

       }

       cache = map;

       return this;

   }

   /**

    * <pre>

    * 对定向内容进行分词,得到单个的定向条件,子类可以重写该方法

    * 默认的分词方法是逗号分隔

    * </pre>

    */

   Set<String> participle(String document) {

       StringTokenizer tokenizer = new StringTokenizer(document, ",");

       Set<String> tokens = new HashSet<>(tokenizer.countTokens());

       while (tokenizer.hasMoreTokens()) {

           tokens.add(tokenizer.nextToken());

       }

       return tokens;

   }

}

step4:获取标签为"深圳"的广告单元id列表。

//通过以下的代码就可以获取标签为"深圳"的广告单元id列表。如斯优雅,而且性能杆杆的。

unitInvertedIndexer.search("深圳");

感谢&总结

 本文主要分享了关于倒排索引的原理以及它的一些应用,在此感谢老大的享。"日拱一卒无有尽 功不唐捐终入海",每天进步一点点,量变引起质变,最后,我们还是可以取得长足的进步的,共勉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱coding的同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值