Combine lower and upper case letters in Android AlphabetIndexer - android

I know that AlphabetIndexer class in Android uses ASCII ordering to order items in the list. It means that if I have items starting for example with lower case "a" it will be ordered after upper case "Z" which seems not so logical. So is there a way to somehow combine lower and upper case letters in such kind of situations?
A good example of success in this is the contacts list of Viber, they don't only managed to put "Y" and "y" in the same section but also show two letters "Yy" in the SectionIndexer. So is it possible to achieve with default AlphabetIndexer? Has anybody some experience with such kind of problem?

It appeared that the solution of this problem is easier but a little bit tricky.
It seems that the problem is not in AlphabetIndexer itself, but in the way the elements are ordered in the cursor that it gets.
So everything I did to solve this problem is to add a right COLLATE to my SQL query.
So I have added the following as a sort order:
private final String SORT_ORDER = Contacts.DISPLAY_NAME_PRIMARY + " COLLATE LOCALIZED ASC";
Note: Contacts.DISPLAY_NAME_PRIMARY is for API 11+ ... for lower APIs you need Contacts.DISPLAY_NAME .
P.S I think this was the only thing that I did to solve this issue, but I don't remember for sure. If it will not help, please tell me and I will look at my code again.

if you want the ordering to not be case sensitive, you need to create your own extension of AlphabetIndexer and overwrite the Compare function to compare the strings in the same case

Related

How to do a simple search in string in Firebase database?

I want to create a simple search in my app, but cannot find anything on interwebs about it, that's more recent than 2014. There must be a better way. There are startAt and endAt functions but they don't work as expected and are case sensitive. How do you guys solve this problem? How can this functionality still not exist in 2016?
In my case I was able to partly achieve a SQL LIKE in the following way:
databaseReference.orderByChild('_searchLastName')
.startAt(queryText)
.endAt(queryText+"\uf8ff")
The character \uf8ff used in the query is a very high code point in the Unicode range (it is a Private Usage Area [PUA] code). Because it is after most regular characters in Unicode, the query matches all values that start with queryText.
In this way, searching by "Fre" I could get the records having "Fred, Freddy, Frey" as value in _searchLastName property from the database.
Create two String variables
searchInputToLower = inputText.getText().toString().toLowerCase();
searchInputTOUpper = inputText.getText().toString().toUpperCase();
Then in the Query set it to:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Products");//Your firebase node you want to search inside..
FirebaseRecyclerOptions<Products> options =
new FirebaseRecyclerOptions.Builder<Products>()//the Products is a class that get and set Strings from Firebase Database.
.setQuery(reference.orderByChild("name").startAt(searchInputUpper).endAt(searchInputLower + "\uf8ff"),Products.class)
.build();
the "name" it's the node inside the Products Main Node.
the .startAt(searchInputUpper) & .endAt(searchInputLower + "\uf8ff") to make the search as contains all characters that typed in the inputText.getText() that you get.
finally I got it you can use where clause to get you result like SQL
LIKE keyword like% or %like
syntax :
Firestore.collection(collectionName).orderBy(field).where(field, ">=", keyword.toUpperCase()).where(field, "<=", keyword.toUpperCase() + "\uf8ff").get()
I my case used:
var query = 'text'
databaseReference.orderByChild('search_name')
.startAt(`%${query}%`)
.endAt(query+"\uf8ff")
.once("value")
In this way, searching by "test" I could get the records having "Test 1, Contest, One test" as value in 'search' property from the database.
Firebase is noSQL therefore it does not have searches built in like you'll find in SQL. You can either sort by values/key or you can equalto
https://firebase.google.com/docs/database/android/retrieve-data
You can find examples at the link above. That is the latest documentation for firebase.
If you are looking for SQL like searches. Then take a look at elastic search. But that will increase the complexity since you need a platform to put it on. For that i could recommend Heroku or maybe GoogleCloudServers
Here is a blog post about advanced searches with elastic search
https://firebase.googleblog.com/2014/01/queries-part-2-advanced-searches-with.html
This question might be old but there is a documented way of how to achieve this way, It is simple to implement. Quoted:
To enable full text search of your Cloud Firestore data, use a third-party search service like Algolia. Consider a note-taking app where each note is a document:
Algolia will be part of your firebase functions and will do all the searches you want.
// Update the search index every time a blog post is written.
exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate(event => {
// Get the note document
const note = event.data.data();
// Add an 'objectID' field which Algolia requires
note.objectID = event.params.noteId;
// Write to the algolia index
const index = client.initIndex(ALGOLIA_INDEX_NAME);
return index.saveObject(note);
});
To implement the search, the best way is to use instant search - android
Sample Search Image: GIF
The feature you're looking for is called full-text search and this is something most databases (including Firebase) don't provide out-of-the-box because it requires storing the data in a format that's optimized for text search (vs optimized for filtering) - these are two different problem sets with a different set of trade-offs.
So you would have to use a separate full-text search engine in conjunction with Firebase to be able to do this, especially if you need features like faceting, typo tolerance, merchandizing, etc.
You have a few options for a full-text search engine:
There's Algolia which is easy to get up and running but can get expensive quickly
There's ElasticSearch which has a steep learning curve but uber flexible
There's Typesense which aims to be an open source alternative to Algolia.
I don't know about the certainty of this approach but using the firebase version 10.2.6 on android, i get to do something like this:
firebaseDatabase.getReference("parent")
.orderByChild("childNode")
.startAt("[a-zA-Z0-9]*")
.endAt(searchString)
It seems to work well sometimes
Finally joined SO just to answer this.
For anyone coming here from/for the python firestore.client here's a solution that seems to work for me.
It's based on the accepted answer's concept but via the client rather than db.reference() and mixed with the answer from user12750908.
from firebase_admin import firestore
users = db.collection("users")\
.order_by("last_name")\
.where("last_name", ">=", last_name.upper())\
.where("last_name", "<=", last_name.lower() + "\uf8ff")\
.stream()
It works for the simple test I did, but I'll update my answer if I have issues with it later. And just a reminder, this is similar to
LIKE search%
and not
LIKE %search%.
Edit 1
I didn't see any tags for the question, but the title attribute mentions Android so this may not necessarily answer the question directly, but if you have a python API, this should work. I'm unfortunately not sure if there's an equivalent client/db separation in the Android version like there is in the Firebase Admin for Python. I didn't want to delete the answer since I hadn't seen any answers for firestore client during my search for a similar answer and hope it helps anyone else stumbling around.
Edit 09-03-2020 This works a portion of the time it seems. Most of the time I didn't seem to have an issue, but when I applied it to another project I was getting unexpected results. Long story short you may need to replicate how you save the data you're comparing against. For example, you may need to have a field to save the last_name in all caps and another field to save it in all lowercase, then you change the first where clause to compare last_name_upper and the second to compare last_name_lowercase. In my second project so far this seems to yield more accurate results so you may want to give that a try if the previous answer doesn't work well
EDIT 09-07-2020 Previous edit from 09-03-2020 is partially accurate. During my haste of thinking I had it fully resolved I completely forgot firebase doesn't let you use <, >, <=, >= across different fields. You may need to do two queries and merge them, but you'd probably still be reading more docs than you really intend. Doing the comparison against either the upper or lower version with the appropriate search term seems to give the original results expected from the original answer. For example:
.orderBy("last_name_upper")
.where("last_name_upper", ">=", this.searchForm.text.toUpperCase())
.where("last_name_upper", "<=", this.searchForm.text.toUpperCase() + "\uf8ff")
As firebase documentation, firebase doesn't support full text search.
But to do that you can use third-party tools.
Check this link to learn more https://firebase.google.com/docs/firestore/solutions/search

How to sort accented letters to be displayed in list view

how do I sort the retrieved data from the database to be displayed as the testing data listed below if there are special characters as the à character?
Apple
ÃTest
Ãbc
Currently this is what I have
query(mDBOpenHelper.getReadableDatabase(),
columnList,selection,selectionArgs, null, null, TestDBOpenHelper.COLUMN1)
When I tested the it on my device, it will display those below after the alphabet Z.
ÃTest
Ãbc
Could someone please teach me how do I fix this? thank you very much
As i know, you won't be able to work with such characters in SQLite as UNICODE,BINARY and LOCAlIZED are the only collation ways to use in sorting. but you can make a work around this. refer to this How to ignore accent in SQLite query (Android)

Regular expression using sqlite in android

I having a difficulty with regex, I have a table products that of one of it`s field is a period.
I want to filter records by a period the user entered in my application.
for example the period might be 2006-2012 or just 2006-
I want to filter all the records that contain only the pattern 2006-
I tried many examples but unfortunately nothing works properly
this is my code
Cursor c = rDB.rawQuery("select title,price from Products,UserProducts where UserProducts.product_code=Prodcuts.product_code and USER_EMAIL=? and Products.period like '%[0-9]+%' group by UserSeries.product_code order by Products.title asc", new String[]{email});
while(c.moveToNext())
{
//save the records
}
Products.period like '%[0-9]+%'
LIKE does not work with regexps.
To use regular expression matching, use the REGEXP operator. Note that by default the REGEXP operator is not implemented, even though the syntax supports it.
For simpler matching needs you can also consider GLOB.
I want to filter all the records that contain only the pattern 2006-
You don't need a regular expression for that.
Products.period like '2006-%'
will match anything where period starts with the string 2006-.
I meant any year with "-" symbol at the end
Products.period like '%-'
will match anything where period ends with the string -.

Android - Do I need to sort a collection for min and max?

I came here (SO) a few days ago to research how to get the min and max from a collection in Android and found a solution to the effect of the following (sorry haven't got a link to the actual answer I used):
Max = (TextView)findViewById(R.id.Max);
Collections.sort(list);
Max.setText(String.format("%.2f", Collections.max(list)));
My question is do I actually need to sort the list before pulling the min/max value? I have tried running the code without sorting the list and it seems to work OK. I am just worried because the answer I used definitely sorted the list first so I assume there must be a reason, I just don't know what it is!
In addition #BobbyDigital's answer who corectly points out the th method iterates over the complete list, I would just like to mention that the result of using the max function might depend on the type of the list elements. If you see the doc , it says that
Returns the maximum element of the given collection, according to the natural ordering of its elements.
If you see Why does Collections.max() not return actual max value for a Collection of String? question, the person used a list of Strings. On extracting max using the abve number he did not get the max number as it was returning the value that's the largest lexicographically. So, just to mention his code:
ArrayList<String> dirNo = new ArrayList<String>();
dirNo.add("1");
dirNo.add("2");
dirNo.add("3");
dirNo.add("4");
dirNo.add("5");
dirNo.add("6");
dirNo.add("7");
dirNo.add("8");
dirNo.add("9");
dirNo.add("10");
dirNo.add("11");
System.out.println("max : " + Integer.parseInt(Collections.max(dirNo))
+ "");
The above code gave 9 as the answer. So be careful while using it. You mgiht want to convert everything to Integer etc based on your needs.
P.S: The example is from the question mentioned and the answer is inspired from this answer by NPE on same question.
No it doesn't have to be sorted. The method iterates over the entire collection.
See the Java docs for the method!

Search Suggestion results displayed as blank/no text

I have included a Search Dialog in my Activity which works fine. However adding Search Suggestions gives me a little problem: The search suggestion entries are "empty".
I can see my content provider gets called (query(..)) and I return a MatrixCursor with several rows. The suggestions list also shows with (clickable) entries -- but are all blank. Blank as if the string I returned for SUGGEST_COLUMN_TEXT_1 and SUGGEST_COLUMN_TEXT_2 where an empty string.
The columns I use in the MatrixCursor are:
String[] columnNames = {"_ID", "SUGGEST_COLUMN_TEXT_1", "SUGGEST_COLUMN_TEXT_2", "SUGGEST_COLUMN_INTENT_EXTRA_DATA"};
I did try with just the _ID and SUGGEST_COLUMN_TEXT_1 column but same result.
EDIT: And I tried returning a simple "test" string as SUGGEST_COLUMN_TEXT_1 instead of something from my data.
I'm note quite sure what code is relevant here, so please ask for whatever may be needed to figure this out.
I have no idea for where to look for this bug, and my Google-Fu has failed me.
Thanks
(I would like to have added an 'android-search-suggestion' tag, but I'm newguy so it seems I cant)
(Thank you, Jcwenger for teaching the new guy :-)
The solution, from my comment above:
Found it. Use SearchManager.SUGGEST_COLUMN_TEXT_1 instead of "SUGGEST_COLUMN_TEXT_1".. (Same for the rest).The String SearchManager.SUGGEST_COLUMN_TEXT_1 maps to "suggest_text_1": http://developer.android.com/reference/android/app/SearchManager.html#SUGGEST_COLUMN_TEXT_1

Categories

Resources