具有 levenshtein 排序和逐字逐句的 Firebase 高级模糊搜索
Firebase advanced fuzzy search with levenshtein ordering and word by word
搜索是我当前应用程序中最重要的部分之一。它需要给人一种快速、准确、全局搜索的感觉。该应用程序基于 Firebase,我发现 Firebase 的 equalTo() / startAt() 组合在这方面相当缺乏。
我想达到的效果:
- 结果按相关性排序
- 逐字匹配(所以 öö pime 应该会产生以上结果)
- 在多个属性中搜索(因此 põhjala pime 应该会产生以上结果)
- 模糊搜索(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 需要根据这个分数进行排序。我的主要问题归结为如何根据上述标准获得最佳分数。任何库或代码示例都将非常受欢迎。
提前致谢。
在尝试自己评分和谷歌搜索失败后,我发现 FuzzyWuzzy。这个相当不错的库使用 levenshtein,但具有 extractTop()
和 extractAll()
功能。它实际上是一个部分模糊搜索,非常适合这种情况。
该库仅在字符串中搜索,但您可以通过创建一个仅包含字符串的数组和一个引用数组来解决这个问题。
搜索是我当前应用程序中最重要的部分之一。它需要给人一种快速、准确、全局搜索的感觉。该应用程序基于 Firebase,我发现 Firebase 的 equalTo() / startAt() 组合在这方面相当缺乏。
我想达到的效果:
- 结果按相关性排序
- 逐字匹配(所以 öö pime 应该会产生以上结果)
- 在多个属性中搜索(因此 põhjala pime 应该会产生以上结果)
- 模糊搜索(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 需要根据这个分数进行排序。我的主要问题归结为如何根据上述标准获得最佳分数。任何库或代码示例都将非常受欢迎。
提前致谢。
在尝试自己评分和谷歌搜索失败后,我发现 FuzzyWuzzy。这个相当不错的库使用 levenshtein,但具有 extractTop()
和 extractAll()
功能。它实际上是一个部分模糊搜索,非常适合这种情况。
该库仅在字符串中搜索,但您可以通过创建一个仅包含字符串的数组和一个引用数组来解决这个问题。