Firebase使用levenshtein排序和逐字逐步进行模糊搜索

时间:2017-04-17 12:50:19

标签: android firebase firebase-realtime-database levenshtein-distance fuzzy-search

搜索是我当前应用程序中最重要的部分之一。它需要感觉像一个快速,准确,全球搜索。该应用基于Firebase,我发现Firebase的equalTo()/ startAt()组合在这方面相当缺乏。

Current situation

我想要实现的目标:

  • 按相关性排序的结果
  • 逐字匹配(因此ööpime应该产生上述结果)
  • 在多个属性中搜索(因此põhjalapime应该会产生上述结果)
  • 模糊搜索(levenshtein?) - pojala 应匹配Põhjala

我已经做了什么

我没有使用equalTo(),而是下载整个分支(例如啤酒),并循环遍历它,执行我自己的contains()。这工作并且相当快。但是,它缺乏我提到的所有东西。这是当前的代码。

           final ArrayList<SearchBeerAdapter.BeerBrewery> searchResults = new ArrayList<>();
            FirebaseUtil.getBeersRef().orderByChild("name").addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(final DataSnapshot ogDS) {
                    int childCounter = 0;
                    for (DataSnapshot ds: ogDS.getChildren()){
                        childCounter++;
                        if (resultCounter[0] < 5) {
                            final Beer beer = ds.getValue(Beer.class);
                            final String beerId = ds.getKey();

                            // Limit to five results and remove listener
                            final int finalChildCounter = childCounter;
                            FirebaseUtil.getBreweriesRef().child(beer.getBreweryId()).addListenerForSingleValueEvent(new ValueEventListener() {
                                @Override
                                public void onDataChange(DataSnapshot dataSnapshot) {
                                    Brewery brewery = dataSnapshot.getValue(Brewery.class);
                                    if (beer.getFullName().toLowerCase().contains(query.toLowerCase()) || brewery.getName().toLowerCase().contains(query.toLowerCase())) {
                                        resultCounter[0] = resultCounter[0] + 1;
                                        if (resultCounter[0] < 5) {
                                            searchResults.add(new SearchBeerAdapter.BeerBrewery(beer, brewery, beerId));
                                        }
                                    }

                                    // Initialize the adapter once we've hit the end of our results
                                    if (finalChildCounter == ogDS.getChildrenCount()){
                                        SearchBeerAdapter sa = new SearchBeerAdapter(searchResults,glide);
                                        rv.setAdapter(sa);
                                    }

                                }

                                @Override
                                public void onCancelled(DatabaseError databaseError) {

                                }
                            });
                        }

                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {

                }
            });

我猜测需要做的是每个匹配需要得到searchResults的分数,在我们完成循环之后,需要按照这个分数对ArrayList进行排序。我的主要问题归结为如何在考虑上述标准的情况下获得最佳分数。任何图书馆或代码样本都将非常受欢迎。

提前致谢。

1 个答案:

答案 0 :(得分:2)

在尝试自己的得分和谷歌搜索失败后,我找到了FuzzyWuzzy。这个相当不错的库使用levenshtein,但具有extractTop()extractAll()功能。它实际上是一种部分模糊搜索,非常适合这种情况。

库只是在Strings中搜索,但您可以通过创建仅字符串数组和引用数组来解决这个问题。