Elasticsearch7.6 之地址解析案例

本文介绍如何利用Elasticsearch 7.6结合IK分词器实现内部网络环境下的地址解析,包括爬取区划数据、创建索引库、数据写入及优化分词库等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景

公司内部网络, 内部物流系统提出需求,通过用户任意输入的地址,自动解析出"省份"-“地市”-“区县”,以及对应的区划代码。

问题分析:

  1. 用户输入地址信息并不标准,无法直接通过数据库检索
  2. 处于内网,无法直接通过互联网获取解析结果
  3. 需要最新的区划数据
    针对以上场景,解决办法就是搭建一个内部的地址解析环境

方案:

1.爬取最新的区划数据
2.使用Elasticsearch7.6,+IK分词器 ,对区划数据做索引文档。并封装调用接口,开放使用。

二、区划数据获取

参考
链接: Python 爬虫 中国行政区划信息爬取.

三、数据准备和写入

平时寄送快递的习惯都会要输入:省市区县+地址信息,因此创建的地址索引内容 也应该包含基础的省市区县甚至街道信息。事例中的地址名称都是标准的行政区划中的名称,也是我们从数据库中获取的数据。
eg:
山东省(省)淄博市(市)沂源县(区县)南鲁山镇(乡镇)平地村委会(村)

 最终封装后的数据模型如下:
              { "address": "山东省淄博市沂源县南鲁山镇上土门村委会",
                "country": "China",
                "countrycode": "0",
                "province": "山东省",
                "provincecode": "370000",
                "city": "淄博市",
                "citycode": "370300",
                "district": "沂源县",
                "districtcode": "370323",
                "xiang": "南鲁山镇",
                "xiangcode": "370323111000",
                "cun": "上土门村委会",
                "cuncode": "370323111213"
                }
向ES 写入的数据时,就是对address字段做分词索引,实现模糊查询。

3.1 创建索引库

根据数据模型,创建索引库如下: http://127.0.0.1:9200/area_index

{
    "settings":{
        "number_of_shards":1,
        "number_of_replicas":0
    },
    "mappings":{
         "properties":{
                "address":{"type":"text", "analyzer":"ik_smart"},
                "country":{"type":"text"},
                "countrycode": {"type":"text"},
                "province":{"type":"text"},
                 "provincecode": {"type":"text"},
                "city":{"type":"text"},
                "citycode": {"type":"text"},
                "district":{"type":"text"},
                "districtcode": {"type":"text"},
                "xiang":{"type":"text"},
                "xiangcode": {"type":"text"},
                "cun":{"type":"text"},
                "cuncode": {"type":"text"}
        }  
    }

}

分词模式使用 ik_smart ,不要使用ik_max_word(拆分的太细了),也只用对address字段做分词。

3.2 数据写入

地址信息数据提前已经导入到了数据库,根据区划的父子关系封装为 (省)-(市)-(区县)南鲁-(乡镇)-(村) 类型的基础视图,这里使用Python脚本将数据从数据库写入到ES中
相关依赖:elasticsearch,sqlalchemy,cx_Oracle

3.2.1 数据库连接脚本

文件名:OracleDb.py


from sqlalchemy import create_engine
from sqlalchemy import MetaData,Table
from sqlalchemy.orm import sessionmaker


class OracleDb:
    def __init__(self, url):
        self.__url = url
        self.__engine = create_engine("oracle://" + url + "")
        self.__session = sessionmaker(self.__engine)


    def findAll(self,mapper):
        db_session = self.__session()
        list= db_session.query(mapper).all()
        db_session.close()
        return list

3.2.2 ES连接

文件名: EsConnect.py

from elasticsearch import Elasticsearch

class EsConn:

    def __init__(self,ip,port):
        self.__ip=ip
        self.__port=port
        self.__db=Elasticsearch([{'host':ip,'port':port}])

    @property
    def db(self):
        return self.__db

3.2.3 ORM映射

t_mv_areainfo_china表,我本地转化好待插入的数据, mapper.py 中的一个对象TMvAreainfoChina,
注:t_mv_areainfo_china 必须得有主键,该文件 通过sqlacodegen.main 生成,其中的getDic()方法自己封装,导入ES时有用。

文件名:mapper.py

# coding: utf-8
from sqlalchemy import Column, DateTime, VARCHAR,CHAR
from sqlalchemy.dialects.oracle import NUMBER
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.oracle import RAW
Base = declarative_base()
metadata = Base.metadata

class TMvAreainfoChina(Base):
    __tablename__ = 't_mv_areainfo_china'

    rid = Column(VARCHAR(64), primary_key=True)
    id = Column(VARCHAR(320))
    address = Column(VARCHAR(1000))
    country = Column(CHAR(5))
    countrycode = Column(CHAR(1))
    province = Column(VARCHAR(200))
    provincecode = Column(VARCHAR(64))
    city = Column(VARCHAR(200))
    citycode = Column(VARCHAR(64))
    district = Column(VARCHAR(200))
    districtcode = Column(VARCHAR(64))
    xiang = Column(VARCHAR(200))
    xiangcode = Column(VARCHAR(64))
    cun = Column(VARCHAR(200))
    cuncode = Column(VARCHAR(64))

	#插入ES时需要转为为标准字典格式,自己封装
    def getDict(self):
        return {
            "id":self.id,
            "address" : self.address,
            "country" : self. country,
            "countrycode" : self.countrycode,
            "province" : self.province,
            "provincecode" : self.provincecode,
            "city" : self.city,
            "citycode" : self.citycode,
            "district" : self.district,
            "districtcode" : self.districtcode,
            "xiang" : self.xiang,
            "xiangcode" : self.xiangcode,
            "cun" : self. cun,
            "cuncode"  : self.cuncode
        }

3.2.4 导入数据

from OracleDb import OracleDb
from EsConnect import EsConn
from elasticsearch import helpers
from mapper import TMvAreainfoChina
cnn=OracleDb('用户名:密码@ip:1521/实例')


AreainfoChina =TMvAreainfoChina
areainfos = cnn.findAll(AreainfoChina )
es = EsConn('127.0.0.1', 9200).db
#批量导入方法
def bulk(es,datalist,index):
    action = ({
        "_index": index,
        "_id": item.id,
        "_source": item.getDict()
    } for item in datalist)
    #print(action.__next__())
    helpers.bulk(es, action)


bulk(es,areainfos,'area_index')
print("******************* end")

导入成功后:测试
在这里插入图片描述

四,这还没完

不要以为这就万事大吉了。实际使用中,解析常常南辕北辙要提高解析准确度,还要对索引做进一步优化

4.1 ik分词库扩展

将所有的地址数据生成dic文件,比如湖北省、湖北、襄阳市、襄阳、东港区、东港 等等,竟可能全面,避免出现错误解析,ik分词的配置略,配置完后需要重新导入数据。
eg:

在这里插入图片描述

在这里插入图片描述

4.2 接口算法优化

ik分词优化后可以提高至少50%解析正确率,要进一步提高准确率,可以提前分词中省、市关键字,对解析出来的结果做进一步过滤。

五 遗留

目前地址解析成功率在80%,主要是用户输入的地址信息并不标准,想要更准确要需要思考更多的办法,笔者对Elasticsearch7.6 使用很少,还望指点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值