Cython: string to list of strings - cython

in pure Python it is easy:
in_string = 'abc,def,ghi,jklmnop,, '
out = in_string.lower().rstrip().split(',') # too slow!!!
out -> ['abc','def','ghi','jklmnop','']
In my case this is called several million times and I need to speed it up a little. I am already using Cython but I do not know not to speed up this particular portion of code.
There can be up to 300 substrings. Pure ASCII. Letters, numbers and some other printable characters. There can be no comma "," in a substring. So a comma is the separator.
Edit:
OK, I see that a simple question turns into a big one. So the data comes from files which have a CSV-like format (no ready to run software works on this) and in total can be 100GB in size. The method reads the file line by line, needs to get the substrings and then sends the substrings to a SQlite database (I am already using executemany). The whole is done in multiprocessing manner, so each file is processed by its own process. The whole is already fast, but I want to squeeze out the last bit of performance. Additionally I want to learn more about Cython. So I have picked this (simple) part of Python code and have run it with "cython -a" which produces a big amount of generated code. So I think this is the best part to start optimizing.
Profiling the code is not that easy because of multiprocessing and cython is being used.
So once someone answers my question, I could implement this code and make a test run. So even I might not improve the speed of my code I will for sure learn a lot. Unfortunately I am a C noob

Yes you can do this in Cython, larger question is if you should.
Where does the input come from?
Is it a file? Then other optimisations are possible, e.g. you could map the file into memory.
Is it a database or network connection? In that case your runtime is probably dominated by waiting for disk/network.
What do you plan to do with the output?
Does the output have to be a string, or can it be a buffer?
"abc,def" -> "abc\0def\0"
buffer1 ------^ ^
buffer2 -----------!
You mentioned that string splitting fragment was called millions of times, processing the string is not that slow, what probably kills performance is allocating all the small strings, an array to hold the result, and then collecting the garbage once substrings are no longer user.
If you could give out pointers to existing data instead, you could speed things up a bit.
How often are these substrings used? If split is called millions of times, it seems to suggest that most substrings are discarded (or you'd run out of memory).
For example, consider the problem "split into substrings and return numbers only"
filter(str.isdigit, "dfasdf,6785,2,dhs,dfgsd,dsg,dsffg".split(","))
If you know in advance that most substrings are not numbers, you'd want to optimise this larger problem as a single block.
How many substrings are there in a typical input?
If there are 4, like in your example, it's not worth it. If there are millions, or even thousands, you may get somewhere.
Is there unicode?
.lower() on an ASCII string is trivial, but not so on unicode. I'd stick to Python if you expect unicode.

Related

Choosing a magic byte least likely to appear in real data

I hope this isn't too opinionated for SO; it may not have a good answer.
In a portion of a library I'm writing, I have a byte array that gets populated with values supplied by the user. These values might be of type Float, Double, Int (of different sizes), etc. with binary representations you might expect from C, say. This is all we can say about the values.
I have an opportunity for an optimization: I can initialize my byte array with the byte MAGIC, and then whenever no byte of the user-supplied value is equal to MAGIC I can take a fast path, otherwise I need to take the slow path.
So my question is: what is a principled way to go about choosing my magic byte, such that it will be reasonably likely not to appear in the (variously-encoded and distributed) data I receive?
Part of my question, I suppose, is whether there's something like a Benford's law that can tell me something about the distribution of bytes in many sorts of data.
Capture real-world data from a diverse set of inputs that would be used by applications of your library.
Write a quick and dirty program to analyze dataset. It sounds like what you want to know is which bytes are most frequently totally excluded. So the output of the program would say, for each byte value, how many inputs do not contain it.
This is not the same as least frequent byte. In data analysis you need to be careful to mind exactly what you're measuring!
Use the analysis to define your architecture. If no byte never appears, you can abandon the optimization entirely.
I was inclined to use byte 255 but I discovered that is also prevalent in MSWord files. So I use byte 254 now, for EOF code to terminate a file.

How to quickly search big text line separated data file?

I've got a big datafile (>= 300M, csv), and want to query data and return line from it.
I can use this method:
grep pattern data.csv
But it is very slow. I need query several patterns, so maybe index this file is a good solution .
Is there any good commandline tool can do this job?
I know there are:
idutils: query is fast, but return result need to access the datafile make it slow.
solr: not that easy to use.
You are missing a lot specifics from your question that would make it easier to help you. For instance, the fields in your CSV, the pattern(s) you typically search upon, if you are searching against the same data set each time, and search frequency. Assuming you need to search against the same data set in ways not supported by grep and/or idutils, Solr makes sense. For instance if you want to do searching that can return partial matches Solr makes this much easier.
While not a command line solution, standing up Solr and loading it with CSV is a straightforward activity. Depending on the size in bytes of your CSV it make not require any tuning. The hard work is defining a Solr schema.xml definition that indexes your data in a way that supports your various search requirements. In your particular case it sounds like you want to do have some tokenization and perhaps stemming done to your searchable fields as you are already looking to do pattern matching. But that really depends on your specific search needs.

How much time does it take one to build the trie

There is a lot of information in the literature which says that the time to search a trie is O(N) where N is the length of the pattern.
However, building the tree will also take some time. To me, let's say there are X words with a total of Y characters.
So then O(Y) is the time (because we have to insert each character). Is this assessment correct (I am usually not correct)
So then O(Y) is the time (because we have to insert each character)
Sure, you have to process each input character, and either follow an existing branch or insert a new char.
It can't be faster then O(Y), since you have to look at each input char. There's neither sorting nor any other operation which could make it slower.
Wrong. Creating a trie and searching a trie are two different algorithms. One wouldn't build a trie, search it, then throw away the entire data structure.

Does having a longer string in a SQL Like expression allow hinder or help query executing speed?

I have a db query that'll cause a full table scan using a like clause and came upon a question I was curious about...
Which of the following should run faster in Mysql or would they both run at the same speed? Benchmarking might answer it in my case, but I'd like to know the why of the answer. The column being filtered contains a couple thousand characters if that's important.
SELECT * FROM users WHERE data LIKE '%=12345%'
or
SELECT * FROM users WHERE data LIKE '%proileId=12345%'
I can come up for reasons why each of these might out perform the other, but I'm curious to know the logic.
All things being equal, longer match strings should run faster since it allows to skip through the test strings with bigger steps and do less matches.
For an example of the algorithms behind sting matching see for example Boyer Moore Algorithm on Wikipedia.
Of course not all things are equal, so I would definitely benchmark it.
A quick check found in the mysql reference docs the following paragraph :
If you use ... LIKE '%string%' and string is longer than three characters, MySQL uses the Turbo Boyer-Moore algorithm to initialize the pattern for the string and then uses this pattern to perform the search more quickly.
No difference whatsoever. Because you've got a % sign at the beginning of your LIKE expression, that completely rules out the use of indexes, which can only be used to match the a prefix of the string.
So it will be a full table scan either way.
In a significant sized database (i.e. one which doesn't fit in ram on your 32G server), IO is the biggest cost by a very large margin, so I'm afraid the string pattern-matching algorithm will not be relevant.

What are important points when designing a (binary) file format? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
When designing a file format for recording binary data, what attributes would you think the format should have? So far, I've come up with the following important points:
have some "magic bytes" at the beginning, to be able to recognize the files (in my specific case, this should also help to distinguish the files from "legacy" files)
have a file version number at the beginning, so that the file format can be changed later without breaking compatibility
specify the endianness and size of all data items; or: include some space to describe endianness/size of data (I would tend towards the former)
possibly reserve some space for further per-file attributes that might be necessary in the future?
What else would be useful to make the format more future-proof and minimize headache in the future?
Take a look at the PNG spec. This format has some very good rationale behind it.
Also, decide what's important for your future format: compactness, compatibility, allowing to embed other formats (different compression algorithms) inside it. Another interesting example would be the Google's protocol buffers, where size of the transferred data is the king.
As for endianness, I'd suggest you to pick one option and stick with it, not allowing different byte orders. Otherwise, reading and writing libraries will only get more complex and slower.
I agree that these are good ideas:
Magic numbers at the beginning. Pretty much required in *nix:
File version number for backwards compatibility.
Endianness specification.
But your fourth one is overkill, because #2 lets you add fields as long as you change the version number (and as long as you don't need forward compatibility).
possibly reserve some space for further per-file attributes that might be necessary in the future?
Also, the idea of imposing a block-structure on your file, expressed in many other answers, seems less like a universal requirement for binary files than a solution to a problem with certain kinds of payloads.
In addition to 1-3 above, I'd add these:
simple checksum or other way of detecting that the contents are intact. Otherwise you can't trust magic bytes or version numbers. Be careful to spec which bytes are included in the checksum. Typically you would include all bytes in the file that don't already have error detection.
version of your software (including the most granular number you have, e.g. build number) that wrote the file. You're going to get a bug report with an attached file from someone who can't open it and they will have no clue when they wrote the file because the error didn't occur then. But the bug is in the version that wrote it, not in the one trying to read it.
Make it clear in the spec that this is a binary format, i.e. all values 0-255 are allowed for all bytes (except the magic numbers).
And here are some optional ones:
If you do need forward compatibility, you need some way of expressing which "chunks" are "optional" (like png does), so that a previous version of your software can skip over them gracefully.
If you expect these files to be found "in the wild", you might consider embedding some clue to find the spec. Imagine how helpful it would be to find the string http://www.w3.org/TR/PNG/ in a png file.
It all depends on the purpose of the format, of course.
One flexible approach is to structure entire file as TLV (Tag-Length-Value) triplets.
For example, make your file comprized of records, each record beginning with a 4-byte header:
1 byte = record type
3 bytes = record length
followed by record content
Regarding the endianness, if you store endianness indicator in the file, all your applications will have to support all endianness formats. On the other hand, if you specify a particular endianness for your files, only applications on platforms with non-matching endiannes will have to do additional work, and it can be decided at compile time (using conditional compilation).
Another point, taken from .xz file spec (http://tukaani.org/xz/xz-file-format.txt): one of the first few bytes should be a non-character, "to prevent applications from misdetecting the file as a text file.". Note sure how many header bytes are usually inspected by editors and other tools, but using a non-binary byte in the first four or eight bytes seems useful.
One of the most important things to know before even starting is how your file will be used.
Will random or sequential access be the norm?
How often will the data be read?
How often will the data be written?
Will you write out the file in one go or will you be slowing writing it as data comes in.
Will the file need to be portable? Not all formats need to be.
Does it need to be compatible with other versions? Maybe updating the file is sufficient.
Does it need to be easy to read/write?
Size/Speed/Compexity tradeoff.
Most answers here give good advise on the portability/compatibility front so I am not going to add more. But consider the following (often overlooked) things.
Some files are often written and rarely read (backups, logs, ...) and you may want to focus on filesize and easy-writing.
Converting endianness is slow (relatively) if your file will never leave the host, or leaves rarely enough that conversion is a good option you can get a significant performance boost. Consider writing a number such as 0x1234 as part of the header so that you can detect (and instruct the user to convert) if this is the case.
Sometimes easy reading is really useful. If you are doing logs or text documents, consider compressing all in one go rather than per-entry so that you can zcat | strings the file and see what is inside.
There are many things to keep in mind and designing a good format takes a lot of planning and foresight. The little things such as zcating a file and getting useful information or the small performance boost from using native integers can give your product an edge, however you need to be careful that you don't sacrifice something important to get it.
One way to future proof the file would be to provide for blocks. Straight after your file header data, you can begin the first block. The block could have a byte or word code for the type of block, then a size in bytes. Now you can arbitrarily add new block types, and you can skip to the end of a block.
I would consider defining a substructure that higher levels use to store data, a little like a mini file system inside the file.
For example, even though your file format is going to store application-specific data, I would consider defining records / streams etc. inside the file in such a way that application-agnostic code is able to understand the layout of the file, but not of course understand the opaque payloads.
Let's get a little more concrete. Consider the usual ways of storing data in memory: generally they can be boiled down to either contiguous expandable arrays / lists, pointer/reference-based graphs, and binary blobs of data in particular formats.
Thus, it may be fruitful to define the binary file format along similar lines. Use record headers which indicate the length and composition of the following data, whether it's in the form of an array (a list of identically-typed records), references (offsets to other records in the file), or data blobs (e.g. string data in a particular encoding, but not containing any references).
If carefully designed, this can permit the file format to be used not just for persisting data in and out all in one go, but on an incremental, as-needed basis. If the substructure is properly designed, it can be application agnostic yet still permit e.g. a garbage collection application to be written, which understands the blobs, arrays and reference record types, and is able to trace through the file and eliminate unused records (i.e. records that are no longer pointed to).
That's just one idea. Other places to look for ideas are in general file system designs, or relational database physical storage strategies.
Of course, depending on your requirements, this may be overkill. You may simply be after a binary format for persisting in-memory data, in which case an approach to consider is tagged records.
In this approach, every piece of data is prefixed with a tag. The tag indicates the type of the immediately following data, and possibly its length and name. Lists may be suffixed with an "end-list" tag that has no payload. The tag may have an embedded identifier, so tags that aren't understood can be ignored by the serialization mechanism when it's reading things in. It's a bit like XML in this respect, except using binary idioms instead.
Actually, XML is a good place to look for long-term longevity of a file format. Look at its namespacing capabilities. If you construct your reading and writing code carefully, it ought to be possible to write applications that preserve the location and content of tagged (recursively) data they don't understand, possibly because it's been written by a later version of the same application.
Make sure that you reserve a tag code (or better yet reserve a bit in each tag) that specifies a deleted/free block/chunk.
Blocks can then be deleted by simply changing a block's current tag code to the deleted tag code or set the tag's deleted bit.
This way you don't need to right away completely restructure your file when you delete a block.
Reserving a bit in the tag provides the the option of possibly undeleting the block
(if you leave the block's data unchanged).
For security, however you might want to zero out the deleted block's data, in this case you would use a special deleted/free tag.
I agree with Stepan, that you should choose an endianess, but I would also have an endianess indicator in the file.
If you use an endianess indicator you might consider using
one of the UniCode Byte Order Marks also as an inidicator of any UniCode text encoding used for any text blocks. The BOM is usually the first few bytes of UniCoded text files, so if your BOM is the first entry in your file there might be a problem of some utility identifying your file as UniCode text (I don't think this is much an issue).
I would treat/reserve the BOM as one of your normal tags (using either the UTF16 BOM if using the 16bit tags or the UTF32 BOM if using 32bit tags) with a 0 length block/chunk.
See also http://en.wikipedia.org/wiki/File_format
I agree with atzz's suggestion of using a Tag Length Value system. For future compatibility, you could store a set of "pointers" to TLV entries at the start (or maybe Tag,Pointer and have the pointer point to a Length,Value; or perhaps Tag,Length,Pointer and then have all the data together elsewhere?).
So, my file could look something like:
magic number/file id
version
tag for first data entry
pointer to first data entry --------+
tag for second data entry |
pointer to second data entry |
... |
length of first data entry <--------+
value for first data entry
...
magic number, version, tags, pointers and lengths would all be a predefined set length, for easy decoding. Say, 2 bytes. Or 4, depending on what you need. They don't all need to be the same (eg, all tags are 1 byte, pointers are 4 etc).
The tag lets you know what is being stored. The pointer tells you where (either an offset or absolute value, in bytes), the length tells you how large the data is, and the value is length bytes of data of type tag.
If you use a MyFileFormat v1 decoder on a MyFileFormat v2 file, the pointers allow you to skip sections which the v1 decoder doesn't understand. If you simply skip invalid tags, you can probably simply use TLV instead of TPLV.
I would either hand code something like that, or maybe define my format in ASN.1 and generate a codec (I work in telecommunications, so ASN.1/TLV makes sense to me :-D)
If you're dealing with variable-length data, it's much more efficient to use pointers: Have an array of pointers to your data, ideally near the start of the file, rather than storing the data in an array directly.
Indirection is preferrable in this instance because it allows random access, which is only possible if all items are the same size. If the data was directly stored in an array, without specifying the locations of any records, data access would take O(n) time in the worst case; in order for your file-reading code to access a particular element it would have to know the length of all previous elements, and the only way to find that out is to look at each one. If you're reading the entire file at once, then you'd be doing this anyway, so it wouldn't be a problem. But if you only want one thing, then this isn't the way to go.
Whereas with an array of pointers, it's O(1) time all around: all you need is an index number, and you can retrieve and follow the pointer to get at your data.
When writing a file using this method, you would of course have to build up your table in memory before doing any writing.