Gossamer Forum
Home : Products : DBMan : Customization :

Random with weighting

Quote Reply
Random with weighting
Hi,

I would like to be able to call 10 random records, however, I would like to have a weight field where it would call those records more frequently. The weight could be as simple as (Frequent? Y/N).

Any ideas?

Thanks in advance.
Adam

Quote Reply
Re: Random with weighting In reply to
Sorry. I don't know how to do that. I have enough trouble just with regular random functions.

JPD
Quote Reply
Re: Random with weighting In reply to
Ok. How about something like this.

A random id of sorts. Each user is randomly assigned a number from 1-10 each time they log in.
Each record is assigned a number from 1-10 as well (I am inputing all records so this would be easy for me to randomize). Then when a user view's all they will see 10 records that include the number they were assgined at login. Only if their login number was duplicated (which it will be at times) will it duplicate the results.

Does this make sense?

Thanks.

Quote Reply
Re: Random with weighting In reply to
Assigning a random number to the user at the time of login is doable, but it's a real pain. The number would have to be included in a hidden field in every form and included in every link so that it "follows" the user from one place to another.

I know you mentioned logging in, but will users have to register before accessing the database, or would they be default users?

JPD
Quote Reply
Re: Random with weighting In reply to
Users would have to register first.

Here is what I am setting up in more detail. For this section of my site I am going to have two versions of dbman running. The first one will be where users will sign up and the database will contain user information that they will be forced to add immediatly after signing up for an account. This database will be add and view. They will only be able to add a single record, and then only be able to view their own record based on their userid field.
The second database will be strictly for viewing records that I have created. It will be using the pass, log and auth from the first but it's own data for viewing. Here there will be only one option -- view listings. This view will be limited to 10 listings per login. To view a new 10 you must log out and then log in again. As i was saying before, the 10 needs to have some form of randomness to it, however it could be the same 10 every couple of logins. (ie: I log in today and get 10, log in tomorrow and get a new 10, 4 days from now I end up getting the same 10 I got the first time. Something like this). Since the database will be maintained by me, and I plan on daily maintence I will be able to assign a number to the listings in a random fashion. Now it's just matching up the listings number with the number assigned to a user at login.

Thanks again.
Adam

Quote Reply
Re: Random with weighting In reply to
That helps more than I can say.

Wait a minute. You said you wanted some kind of weighting, right? I just thought of something. You could add together a certain number of random numbers, which would end up giving you a "bell curve" of possibilities.

For example, if you added 3 random numbers, each ranging from 1 to 4, you would get the following probability distribution:

3 -- 1
4 -- 3
5 -- 6
6 -- 10
7 -- 12
8 -- 12
9 -- 10
10 -- 6
11 -- 3
12 -- 1

If you wanted to keep your numbers from 1 to 10, you would just need to subtract 2 from the total. So computing the random number for the user would be:

Code:

for ($r=1;$r<4 ;++$r) {
$in{'random'} += int(rand(4)) + 1;
}
$random -= 2;
I'm not quite sure what you would do with it, though. If you assigned the records based on the distribution, users would have different probabilities of getting a certain list, but not different probabilities of getting a certain record. Is that what you want?

Of course, you could use any numbers you wanted -- random numbers ranging from 1 to whatever and any number of random numbers added together. It would all result in a bell curve sort of weighting. (I got all this from remembering when I used to play tabletop role-playing games. Smile)

The thought I had was to generate the random number at the time the user signs in and saving it to the session file for the user. This has several advantages. One is that you don't have to add hidden fields to your forms and text to your links in order to pass the random number each time the script is invoked. The other is that the user could not change his random number in the URL.

To do this, in auth.pl, sub auth_check_password, change

print AUTH "$uid: $ENV{'REMOTE_HOST'}\n";

to

Code:

$in{'random'} = whatever your random number generation routine is;
print AUTH "$in{'random'}\n";
Then in sub auth_check_permissions, before

open (PER, "<$auth_pw_file") or &cgierr("

add

Code:

open(AUTH, "<$auth_dir/$db_uid") or &cgierr("unable to open auth file: $auth_dir/$uid. Reason: $!\n");
@random=<AUTH>;
close AUTH;
$in{'random} = $random[0];
chomp $in{'random'};
In fact, the best thing to do would be to either name your field with your random numbers random or to change every instance of $in{'random'} above to match your fieldname. That way when you did a search, the search term would always be there. I don't think you would have to add any more code.

A couple of other things I've thought of while writing this: You should probably only have as many records with a given number as will fit on a page. IOW, if your $db_max_hits is set to 10, then you should only have 10 records with the number 6 in the random field.

The other thing is that you should probably set $in{'ww'}=1 always in sub query. Otherwise, if the user's number is 1, he will get both records with 1 and with 10 in the field.

Let me know if this is all clear as mud. Smile

JPD
Quote Reply
Re: Random with weighting In reply to
WOW!

The concept behind what you just said makes perfect sense and sounds like it should work.
You remember it from role playing, I get from my economics background....but it works Smile
I need to do a litte more work on the database before trying the codes though.

Different probablilites of getting a certain list is exactly it. I want to be able to create the lists, which I will change periodically on my own.

There is no need to keep the number between 1 and 10, it was just for example purposes. As you provided the code it makes sense how to modify to the appropriate number. In the distribution you exampled, there are 64 possible outcomes so at the most the 7 or 8 would come up 18.75% of the time each. That's not bad because I don't care if the number is repeated a few days later. Just as long as it's not repeated the next day. The odds are in that favor of that and if it is a few times then that's no big deal.

You have a great idea about writing that into the session file and preventing change.
It will also be quite easy for me to keep the number of records for example with the number 6 to 10 and no more.

Thanks for the great suggestions!

Quote Reply
Re: Random with weighting In reply to
Now I see why you asked your other question. You don't want people to just re-login to get a different list. Smile

What I suddenly thought of when I was writing my previous post was rolling three dice to get a number from 3 to 18 in the role-playing games. The statistics of it comes from my education in psychology. (I didn't spend *all* my time playing games!!! Laugh) Then again, the first programs I wrote were for generating character stats by "rolling the dice" three times. The nice thing about using a program, though, is that you can have a "17-sided die" if you want to. Smile

It's nice to know that all the time I did waste on those games is coming in handy!! Laugh

JPD
http://www.jpdeni.com/dbman/
Quote Reply
Re: Random with weighting In reply to
Well I'm working on this section now and am running into some problems.

For starters:
1. Where you have "whatever your random number generation routine is" how do I put the routine you indicated above into that spot?

2. When I do the search on the random field based on the number generated, how do I call that number out of the auth file where it was written?
---------------------------edited below--------------
3. Is it possible if a user goes back to the login screen for it to check first if there is an active auth file to use before creating a new one?
----------------- Sorry, I remembered after I posted this that I already got the answer to this one and it works.

Thanks!
Adam

Quote Reply
Re: Random with weighting In reply to
In Reply To:
Where you have "whatever your random number generation routine is" how do I put the routine you indicated above into that spot?
If you're using the "weighted number from 1 to 10" code that I posted, it would be

Code:

for ($r=1;$r<4 ;++$r) {
$in{'random'} += int(rand(4)) + 1;
}
$in{'random'} -= 2;
print AUTH "$in{'random'}\n";
In Reply To:
2. When I do the search on the random field based on the number generated, how do I call that number out of the auth file where it was written?
The best way to do this would be to set up a new function. In your link to do the random records, use

<a href="$db_script_link_url&random=1">View Random</a>

In db.cgi, sub main, after

elsif ($in{'view_records'}) { if ($per_view) { &view_records; } else { &html_unauth; } }

add

elsif ($in{'random'}) { if ($per_view) { &random_records; } else { &html_unauth; } }

Also in db.cgi, add a new subroutine:

Code:

sub random_records {
open (AUTH, "<$auth_dir/$db_uid") or
&cgierr("error in random_records. unable to open file: $auth_dir/$db_uid.\nReason: $!");
if ($db_use_flock) { flock(AUTH, 1); }
@lines = <AUTH>;
close AUTH;
$in{'Random'} = shift @lines;
chomp $in{'Random'};
$in{'ww'} = 1;
my ($status, @hits) = &query("view");
if ($status eq "ok") {
&html_view_success(@hits);
}
else {
&html_view_failure($status);
}
}
Change Random to match the name of your random number field.

In Reply To:
3. Is it possible if a user goes back to the login screen for it to check first if there is an active auth file to use before creating a new one?
Hmmmmm. You do have sneaky users!! Smile

In auth.pl, sub auth_check_password, after

elsif ($in{'login'}) { # The user is trying to login.

add

Code:

opendir (AUTHDIR, "$auth_dir") || &cgierr("unable to open directory: $auth_dir. Reason: $!");
@files = readdir(AUTHDIR); # Read in list of files in directory..
closedir (AUTHDIR);
FILE: foreach $file (@files) {
next if ($file =~ /^\./); # Skip "." and ".." entries..
next if ($file =~ /^index/); # Skip index.htm type files..
($file =~ /^([A-Za-z0-9]+)\.\d+$/) ? ($username = $1) : next;
if ($username eq $in{'userid'}) {
return ('ok', $file, &auth_check_permissions($file));
}
}
Now, I haven't tested this, but it should work.

JPD
http://www.jpdeni.com/dbman/
Quote Reply
Re: Random with weighting In reply to
You're a genius!!

Through inital testing it seems to be working perfectly. I need to do some more testing of course (to make sure those tricky users don't get by) :-)
In Reply To:
<a href="$db_script_link_url&random=1">View Random</a>
I'm not sure if this code is necessary. The general list all is bringing back only those records with the random number in it, so somewhere else you already covered it.

As I edited above, sorry I asked the question again about logging in a second time. I tried to add the link above but it didn't seem to be working correctly. Here is the previous response you gave to my last question.
http://gossamer-threads.com/...ew=&sb=&vc=1
Thanks a million for all the great help!
Adam

Quote Reply
Re: Random with weighting In reply to
Well, there are different ways of doing the same thing. Smile

Is everything working, whether by my most recent code or using something else?

JPD
http://www.jpdeni.com/dbman/
Quote Reply
Re: Random with weighting In reply to
I have been testing all morning and finally found a real problem. It's related to the last part where I want it to check for an existing log file.

The problem is two fold. First I noticed that it will not add another line to the log file for the subsequent login with an existing auth file. Then I noticed that it does no password check, any password with login admin would work once the true admin has created an auth file. So my changes were as follows:
Instead of after:

elsif ($in{'login'}) { # The user is trying to login.

Put after:

if (($in{'userid'} eq $userid) && (crypt($in{'pw'}, $pw) eq $pw)) {

This:

opendir (AUTHDIR, "$auth_dir") || &cgierr("unable to open directory in auth_check_password: $auth_dir. Reason: $!");
@files = readdir(AUTHDIR); # Read in list of files in directory..
closedir (AUTHDIR);
FILE: foreach $file (@files) {
next if ($file =~ /^\./); # Skip "." and ".." entries..
next if ($file =~ /^index/); # Skip index.htm type files..
if ($file =~ /^$in{'userid'}\./) {
$db_uid = $file;
&auth_logging('logged on', $userid) if ($auth_logging);
return ('ok', $db_uid, &auth_check_permissions($db_uid));
}
}


This allows for the password check, and the logging. Notice that I used the original code you provided me. I had not tried your new code. I also added the &auth_logging line as well.

Now it appears that all is working properly. If someone logs in it does a check through the .pass and verifies the login and password. Then it checks the auth files for an existing file. If it exists it logs the action and then enters the db, if it doesn't exist then it continues like normal creating a random number and auth file.

Adam

Quote Reply
Re: Random with weighting In reply to
So it's working now? Smile

JPD
http://www.jpdeni.com/dbman/
Quote Reply
Re: Random with weighting In reply to
Seems to be.....thanks!

Quote Reply
Re: Random with weighting In reply to
Well here's an update. Remember that I said that view all limited itself to the random records only. This turns out that it would be a problem with one of my other db's that uses the same auth file. That db has no random field and would just crash.

It turns out in the sub auth_check_permissions you included $in{'Random'} = $Random[0]; and unless I am wrong (which is usually the case) what this is doing is comparing the random number in the auth file to the random field in the .db As a result, it only pulls back the records that have the random number it in the view all option, or any viewing option.

By taking out that line, I was able to view all successfully. And I am able to view random using the link to do the random numbers &random=1 .

So far so good.....anything I might be wary about though?

Thanks!
Adam

Quote Reply
Re: Random with weighting In reply to
I'm not even sure what is going on. You're doing better than I am today. Smile


JPD
http://www.jpdeni.com/dbman/
Quote Reply
Re: Random with weighting In reply to
I think I must I enjoy making life hard.
My reasoning for the following is to incorporate the session cookie mod.

Now I would like to change where it prints in the auth file
print AUTH "$in{'random'}\n";
to
print AUTH "$in{'random'}:$view:$add:$del:$mod:$admin:$ENV{'REMOTE_HOST'}\n";
This works fine.

The problem I am running into is calling back just the $in{'random'}
I know it's somewhere in here that needs to be changed:

sub random_records {
open (AUTH, "<$auth_dir/$db_uid") or
&cgierr("error in random_records. unable to open file: $auth_dir/$db_uid.\nReason: $!");
if ($db_use_flock) { flock(AUTH, 1); }
@lines = <AUTH>;
close AUTH;
$in{'Random'} = shift @lines;
chomp $in{'Random'};
$in{'ww'} = 1;
my ($status, @hits) = &query("view");
if ($status eq "ok") {
&html_view_success(@hits);
}
else {
&html_view_failure($status);
}
}


Using something that would split each : and put each value into it's own variable.
Exactly how to do this is beyond me....I tried a lot in the last hour. *sigh*

Thanks!
Adam

Quote Reply
Re: Random with weighting In reply to
Change

Code:

$in{'Random'} = shift @lines;
chomp $in{'Random'};
to

Code:

$line = shift @lines;
chomp $line;
($in{'Random'},@rest) = split /:/,$line;
Be sure that the variable has the right name. $in{'Random'} is not the same as $in{'random'}.



JPD
http://www.jpdeni.com/dbman/