【问题标题】:Matching algorithm for objects in Java + HibernateJava + Hibernate中对象的匹配算法
【发布时间】:2018-03-17 15:24:35
【问题描述】:

我正在用 Spring MVC 和 Hibernate 编写一个应用程序,我正在研究它。我有 12 个变量的对象 Person。任务是从数据库中找到与可比对象最佳匹配的现有对象 Person。例如 9 个变量的 inputPerson_1 匹配 databasePerson_423 是 75% 匹配。

我有以下想法,但它看起来对数据库来说非常重载,显然是一个弱解决方案:

1) 向 MySQL 创建 12 个连续查询以收集所有可能的匹配对象并保存到 HashSet,其中第一个参数将是 Person ID

query = session.createQuery("from Person where lower(firstName) like :inputFirstName) 
query = session.createQuery("from Person where lower(lastName) like :inputLastName) 
...

2) 创建 int max 并从 HashSet 中逐一比较对象的变量。返回匹配度最高的对象。

最好的选择是什么?也许有一些现成的解决方案?

【问题讨论】:

    标签: java mysql spring algorithm hibernate


    【解决方案1】:

    我只会执行一个数据库查询,它会搜索任何属性是否匹配。

    然后我会写一个函数来计算每个人有多少属性匹配并返回一个最佳匹配值。

    然后您可以对列表进行排序以获得最佳匹配值。

    当然,有无数种方法可以解决问题,并且每种方法都有自己的优点和缺点。

    所以,以下是我建议的解决方案的优缺点:

    专业人士:

    • 您与数据库的交互较少。 => 它应该是比答案中的更快的解决方案。
    • 您对最佳匹配的计算非常灵活。这是一项功能,您可以在其中检查和计算几乎所有您想要的东西。

    缺点:

    • 您在不同的地方有两个部分必须保持同步。搜索所有条件的数据库查询和检查相同属性的计算函数。 => 隐藏的契约和耦合

    • 如果搜索条件将返回大量条目,则此解决方案不适合。然后你必须以某种方式计算数据库内的因子,并且你需要使用与 order 和 limit 一起使用的索引,所以你不会返回所有行并且有一个 O(log(n)) 的努力类。

    【讨论】:

      【解决方案2】:

      也许有人会发现这个答案对自己的提议很有用...... 我决定现在采用最简单的方法。 寻找相似的对象:

      public List<Person> searchSimilarPeople(Person person) {
          Session session = sessionFactory.getCurrentSession();
          Query query = null;
          query = session.createQuery("from Person where lower(firstName) like :s_name or lower(lastName) like :f_name " +
                  "or lower(email) like :email or lower(address1) like :address1 or lower(address2) like :address2 " +
                  "or lower(city) like :city or lower(region_state) like :state or lower(zip) like :zip " +
                  "or lower(country) like :country", Person.class);
          query.setParameter("s_name", "%" + person.getFirstName() + "%");
          query.setParameter("f_name", "%" + person.getLastName() + "%");
          query.setParameter("address1", "%" + person.getAddress1() + "%");
          query.setParameter("address2", "%" + person.getAddress2() + "%");
          query.setParameter("city", "%" + person.getCity() + "%");
          query.setParameter("state", "%" + person.getRegion_state() + "%");
          query.setParameter("zip", "%" + person.getZip() + "%");
          query.setParameter("country", "%" + person.getCountry() + "%");
          query.setParameter("email", "%" + person.getEmail() + "%");
          return query.getResultList();
      }
      

      我尝试过使用 Lucene 深入研究 Hibernate Search 过程,但我认为它对于 Hibernate 初学者来说并不是最佳选择。但如果有人使用 Lucene 提供相同过程的简要说明,我将不胜感激:)

      对象比较: 比较对象中的几乎所有变量都是字符串,所以我决定使用 Jaro-Winkler 距离来获得字符串匹配系数,然后将其乘以 0.11(我有 9 个变量要比较,因此最大可能匹配结果为 0.99)

       @Override
      public Double getMatch(Person inputPerson, Person dbPerson) {
          double intermResult = 0;
          double finalResult = 0;
          // FirstName
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getFirstName().toLowerCase(), dbPerson.getFirstName().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
          // LAST NAME
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getLastName().toLowerCase(), dbPerson.getLastName().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
          // Email
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getEmail().toLowerCase(), dbPerson.getEmail().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
          // ADDRESS 1
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getAddress1().toLowerCase(), dbPerson.getAddress1().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
          // ADDRESS 2
          if (inputPerson.getAddress2() != null && dbPerson.getAddress2() != null) {
              intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getAddress2().toLowerCase(), dbPerson.getAddress2().toLowerCase());
              finalResult += (intermResult * rateCoefficient);
          }
          // CITY
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getCity().toLowerCase(), dbPerson.getCity().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
          // STATE
          if (inputPerson.getRegion_state() != null && dbPerson.getRegion_state() != null) {
              intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getRegion_state().toLowerCase(), dbPerson.getRegion_state().toLowerCase());
              finalResult += (intermResult * rateCoefficient);
          }
          // ZIP
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getZip().toLowerCase(), dbPerson.getZip().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
          // COUNTRY
          intermResult = StringUtils.getJaroWinklerDistance(inputPerson.getCountry().toLowerCase(), dbPerson.getCountry().toLowerCase());
          finalResult += (intermResult * rateCoefficient);
      
          finalResult = Precision.round(finalResult, 3);
          System.out.println("Final Result. ID : " + dbPerson.getId() + " " + finalResult);
          return finalResult;
      }
      

      【讨论】:

        猜你喜欢
        • 2014-12-05
        • 1970-01-01
        • 2012-12-17
        • 1970-01-01
        • 2013-05-07
        • 2016-04-19
        • 1970-01-01
        • 2014-12-01
        • 2017-06-07
        相关资源
        最近更新 更多