基于MATLAB的简易搜索引擎制作举例

摘要

某些行业中用户所需商品的名称专业性较强,普通的搜索引擎较难满足要求。因此基于MATLAB设计一个以垂直搜索引擎为架构的搜索模型。以某品牌拖拉机的零部件作为商品为例来演绎算法。

算法思想

在这里插入图片描述
通过确定用户输入的字符串中是否包含有从上到下的层的关键词,从而一级一级的缩小范围,直到找到目标商品为止。如果用户输入的信息不足的话则会给出能够根据当前信息推断出的所有的零件

问题引入

用户的描述和厂商对零部件的分类名称有较大的出入,如下:

普通用户:品牌车型配件名

厂家: 型号器件部件零件, 每个零部件对应唯一的配件编码

卖家:发动机部件滤芯长城哈弗H62018款, 也会将每个配件对应唯一的配件编码

其中的关键是在用户描述和零部件唯一配件编号之间设计匹配算法。

代码实现

根据得到的厂家商品文件说明书,我们先观察其特征并分析,商品说明书主要页面格式如下:
在这里插入图片描述
在这里插入图片描述

文件操作部分

在进行文件操作前,要先把pdf文件的说明书的相关内容拷贝到txt文件中。如下图示:
(所有txt附件若有需要请评论留言,看必回)

在这里插入图片描述

我们先必须读取商品说明书的目录,接下来写一个函数读取目录:

function  cpfind= fun_getnameidx( filename )
fid = fopen(filename,'rt');%read text, 'rt'
n= 0;%文件行数,
m=0;%第几个小零件
while ~feof(fid)  % file operation, end of file
    str = fgetl(fid);%读取行 
    if isempty(str)
        break       
    end
    if str(1)=='!'
        if n~=0
            for i=1:0.5*n
         cpfind{m-2,i}= cpfind{m-2,0.5*n+i};
         cpfind{m-2,0.5*n+i}=[];
            end
        end
         if length(str)==1;
            break
        end
        if length(str)==2
        m=str2num(str(2));
        else
        m=str2num(str(2:3));
        end
        n=0;        
    end
    
  if str(1)~='!'
       str(isspace(str)) = []; %去除所有空格
       t=find(str=='.');
   if isempty(t)
        cpfind{m-1,n+1}=str;
   elseif t(1)==2&&(str(1)=='0'||str(1)=='1')
        cpfind{m-2,n+1}=str(1:t(2)-1);
   elseif t(1)==1&&str(2)=='0'
        cpfind{m-2,n+1}=str(2:t(3)-1);
     elseif t(1)==1&&t(2)>2
        cpfind{m-2,n+1}=str(2:t(2)-1);        
      elseif t(1)==1&&t(2)==2&&t(3)>3
        cpfind{m-2,n+1}=str(3:t(3)-1);    
    elseif t(1)==1&&t(2)==2&&t(3)==3
        cpfind{m-2,n+1}=str(4:t(4)-1);  
         elseif t(1)==1&&t(2)==2&&t(3)==3&&t(4)==4
        cpfind{m-2,n+1}=str(5:t(5)-1);  
   else     
       cpfind{m-2,n+1}=str(1:t(1)-1);
   end

    n=n+1;
 end
end


fclose(fid);
end


读取具体每一页的部件内容:

function partnp=fun_getnamepagenum(filename)
fid = fopen(filename,'rt');%read text, 'rt'


n= 0; s(find(isspace(s))) = [] %去除所有空格
m=0;
while ~feof(fid)  % file operation, end of file
    str = fgetl(fid);
     str(isspace(str)) = []; %去除所有空格
    if isempty(str)
        break
    end
    if  str(1)=='!'
        m=m+1;
        n=0;
    continue    
    end
    t=find(str=='.');
    if isempty(t)
        break
    end
    if ~isempty(strfind(str,'0.2'))
         partnp{2*m,n+1}=str(1:t(2)-1);
    else
         partnp{2*m,n+1}=str(1:t(1)-1);
    end
   
   
    if str(end-1)=='-'
        partnp{2*m-1,n+1}=str2num(str(end));
    else
        partnp{2*m-1,n+1}=str2num(str(end-1:end));     
    end
    n=n+1;
end

fclose(fid);

结果如下:
在这里插入图片描述

字符串编辑距离计算函数

这里我们用到了字符串编辑距离来进行模糊判断,就是能够容许一定的关键词错误率。
结果如下:在这里插入图片描述
可以看到我们故意输入错误的链轮和惰轮缓冲器均被纠正并识别出来了。
代码如下:

function V= editdist(string1,string2)

m=length(string1);
n=length(string2);
v=zeros(m+1,n+1);
for i=1:1:m
    v(i+1,1)=i;
end
for j=1:1:n
    v(1,j+1)=j;
end
for i=1:m
    for j=1:n
        if (string1(i) == string2(j))
            v(i+1,j+1)=v(i,j);
        else
            v(i+1,j+1)=1+min(min(v(i+1,j),v(i,j+1)),v(i,j));
        end
    end
end
V=v(m+1,n+1);
end

主函数部分

clear all
clc

%目标:完成用户到idx值的匹配

%基本关系,器件大于部件大于零件

%名称说明:partinf----器件下(部件-page)元胞矩阵
%                  compoinf--------(零件-idx值)元胞矩阵
feature('DefaultCharacterSet','UTF-8');%将默认字符改为支持中文的格式

%接下来输入一共5级信息元胞
brandinf={'小松'};
typeinf={'PC56'};
deviceinf={'发动机','发动机相关零件','冷却系统','燃油箱及相关零件','电气系统','液压系统','主机架/转台及相关零件','驾驶室及控制系统','护罩','回转支承及相关零件','行走和下部配管','下部行走体','工作装置','标志和标牌','附件','服务工具包及相关零件'};  
partinf=fun_getnamepagenum('idx.txt');%读取附件的目录内容,得到部件名称跟页面的索引
compoinf=cell(1600,100);%初始化 零件-idx 元胞矩阵,每100行储存一个器件下所有部件下所有零件对应的idx值
%接下来进行上述元组(compoinf)的获取
for i = 1:16%16次循环,因为根据附件,一共有16个器件
filename = ['compoidx\' num2str(i) '.txt'];
txtfile= fun_getnameidx(filename);%调用零件-idx值读取函数
h=size(txtfile);%得到某次读取的器件的元组的大小
for m=1:h(1)
    for n=1:h(2)
        compoinf{100*(i-1)+m,n}=txtfile{m,n};%将某次读取的器件的全部信息一一录入零件-idx值元胞矩阵
    end
end
end

cmk=cell(1,10);cmk{1}=char('小松PC56推土铲总成');cmk{2}=char('PC56怠速设定adc装cds置');cmk{3}=char('小松牌PC56型号散热器和油冷却器带粗滤板的');cmk{4}=char('小松PC56排气套筒');cmk{5}=char('小松PC56主阀弯头支座隔套');cmk{6}=char('小松PC56回油油路上的垫圈');cmk{7}=char('小松PC56下部液压配管上的软管总成');cmk{8}=char('小松PC56支重轮');
cmk{9}=char('小松PC56动臂油缸卡环');cmk{10}=char('PC56链cd轮');cmk{11}=char('小松56堕轮缓ad冲器advd油缸');





for www=1:11
%------------------------------------------------------------------------------------------------------------
cm=cmk{www};%用户输入
%------------------------------------------------------------------------------------------------------------

%接下来实现匹配算法
idname=cell(1,5);%初始化一共5级的详细零件名矩阵。
idx={};

sb=size(brandinf);
st=size(typeinf);
sd=size(deviceinf);
sp=size(partinf);%得出元组的大小

%%%%%%%%%%%%%%%%%%品牌名检索%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
brandname=[];
for i=1:sb(2)
     fb=strfind(cm,brandinf{1,i});
    if ~isempty(fb)
        brandname=brandinf{1,i};
        brandnum=i;
        break
    end
end
idname{1}=brandname;
if isempty(idname{1})
brandname=[];
fb=zeros(sb(2),1);
for i=1:sb(2)
     fb(i)=editdist(cm,brandinf{1,i});
end
brandnum=find(fb==min(fb));
brandname=brandinf{1,brandnum};
idname{1}=brandname;
end

%%%%%%%%%%%%%%%%%%%机型名检索%%%%%%%%%%%%%%%%%%%%%%%%%%%
lt=0;
for i=1:st(2)%统计某一品牌中机型的个数
    if ~isempty(typeinf{brandnum,i})
        lt=lt+1;
    end
end
typename=[];
for i=1:lt
     ft=strfind(cm,typeinf{brandnum,i});
    if ~isempty(ft)
        typename=typeinf{brandnum,i};
        typenum=i;
        break
    end    
end
idname{2}=typename;
if isempty(idname{2})
ft=zeros(lt,1);
for i=1:lt
     ft(i)=editdist(cm,typeinf{brandnum,i});
   
end
typenum=find(ft==min(ft));
typename=typeinf{1,typenum};
idname{2}=typename;
end
%%%%%%%%%%%%%%%%器件名检索%%%%%%%没用编辑长度%%%%%%%%%%%%%%%%%%
ld=0;
devicename=[];
for i=1:sd(2)%统计某一机型中器件的个数
    if ~isempty(deviceinf{typenum,i})
        ld=ld+1;
    end
end
for i=1:ld
     ft=strfind(cm,deviceinf{typenum,i});
    if ~isempty(ft)
        devicename=deviceinf{typenum,i};
        devicenum=i;
        break
    end    
end
if ~isempty(devicename)
     
      idname{3}=devicename;  
end
%%%%%%%%%%%%%%%%%%%%%%部件名检索%%%%%%%%%%%%%%%%%%%%%
partname=[];
pagenum=zeros(1,2);
if isempty(devicename) 
for ii=1:0.5*sp(1)
     for jj=1:sp(2)
         k=strfind(cm,partinf{2*ii,jj});%一个个匹配
         if ~isempty(k)
             partname=partinf{2*ii,jj};%输出找到的部件名
             pagenum(1)=ii-1;%第几百个,在compoinf中
             pagenum(2)=partinf{2*ii-1,jj}-1;%某百行中具体的位置
             idname{3}=deviceinf{typenum,ii};
             %在compoinf中的行序号计算为:100*pagenum(1)+pagenum(2)
             break           
         end   
     end 
end 
if isempty(partname)%%%%%%%%%%开始模糊匹配%%%%%%%
  k=zeros(0.5*sp(1),sp(2));
p=zeros(1,sp(2));
for ii=1:0.5*sp(1)
     for jj=1:sp(2)
         k(ii,jj)=editdist(cm,partinf{2*ii,jj});%一个个匹配     
     end  
end
[hh,gg]=find(k==min(min(k)));%找到某个算出的编辑距离矩阵中最小值,可能有多个。。。
%为防止有多个最小值出现的情况,比较这两个名字与目标语句的字符相似个数
x=length(hh);
y=0;
cnt=zeros(1,x);
for e=1:x%%%%%%%%%%%%%%开始模糊匹配二次验证%%%%%%%%%%%%%
      y=length(partinf{2*hh(e),gg(e)});
      cnt(e)=0;
      tmp=0;
      for u=1:y
            tmp=length(strfind(cm,partinf{2*hh(e),gg(e)}(u)));
            cnt(e)=cnt(e)+tmp;
      end
end
fh1=find(cnt==min(cnt));
fh2=fh1(1);
h_=hh(fh2);g_=gg(fh2);
partname=partinf{2*h_,g_};
pagenum(1)=h_-1;
pagenum(2)=partinf{2*h_-1,g_}-1;
idname{3}=deviceinf{typenum,h_};  
end
else    
    for jj=1:sp(2)
         k=strfind(cm,partinf{2*devicenum,jj});%一个个匹配
         if ~isempty(k)
             partname=partinf{2*devicenum,jj};%输出找到的部件名
             pagenum(1)=devicenum-1;%第几百个,在compoinf中
             pagenum(2)=partinf{2*devicenum-1,jj}-1;%某百行中具体的位置
             %在compoinf中的行序号计算为:100*pagenum(1)+pagenum(2)
             break           
         end 
    end
    if isempty(partname)%%%%%%%%%%开始模糊匹配%%%%%%%
     for jj=1:sp(2)
         p(jj)=editdist(cm,partinf{2*devicenum,jj});%一个个匹配        
     end
tt=find(p==min(p));
x=length(tt);
y=0;
cnt=zeros(1,x);
for e=1:x%%%%%%%%%%%%%%开始模糊匹配二次验证%%%%%%%%%%%%%
      y=length(partinf{2*devicenum,tt(e)});
      cnt(e)=0;
      tmp=0;
      for u=1:y
            tmp=length(strfind(cm,partinf{2*devicenum,tt(e)}(u)));
            cnt(e)=cnt(e)+tmp;
      end
end
fh1=find(cnt==min(cnt));
fh2=fh1(1);
h_=tt(fh2);
partname=partinf{2*devicenum,h_};
pagenum(1)=devicenum-1;
pagenum(2)=partinf{2*devicenum-1,h_}-1;
    end
end
idname{4}=partname;
ri=100*pagenum(1)+pagenum(2);%算出具体在那一行,模拟上就是翻书到了画有部件图的某一页上去了

%%%%%%%%%%%%%%%%%%%%%%%%%零件名字匹配%%%%%%%%%%%%%%%%%%%%%%%%%
lc=0;
for i=1:100%统计某一页中零件的个数
    if ~isempty(compoinf{ri,i})
        lc=lc+1;
    end
end
muticompo=[];
%%%%%%%%%%%%%%%%%精确匹配尝试%%%%%%%%%%%%%%%%%%%%%%%%%%%
for q=1:lc
    f=strfind(cm,compoinf{ ri,q});%在那一行一个一个的比较%该处的比较考虑用更复杂的语法,纠错分析
    if ~isempty(f)
        componame=compoinf{ri,q};%匹配到了目标字符
    if isempty(find(strcmp(compoinf{ri+1,q},idx), 1))%检验之前是否放入过同样型号的零件
        idx=[idx,compoinf{ri+1,q}]; %拼接零件号
        muticompo=[muticompo,q];
    end
    end
end

%%%%%%%%%%%%%%%%%%%模糊匹配尝试%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if isempty(muticompo)
rr=zeros(1,lc);
for q=1:lc
    rr(q)=editdist(cm,compoinf{ ri,q});%在那一行一个一个的比较%该处的比较考虑用更复杂的语法,纠错分析  
end
pcop=find(rr==min(rr));
for m=1:length(pcop)
    f=pcop(m);
    if isempty(find(strcmp(compoinf{ri+1,f},idx), 1))%检验之前是否放入过同样型号的零件
        idx=[idx,compoinf{ri+1,f}]; %拼接零件号
        muticompo=[muticompo,f];
    end
end

end


whname={};
for i=1:length(muticompo)
    longname=[];
    idname{5}=compoinf{ri,muticompo(i)};
    for j=1:5
    longname=[longname,idname{j}];
    end
    whname=['您的输入是:',cmk{www},'-------您要找的是不是:',longname,'-----',idx{i}];
    disp(whname)
end


end

结果实例:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值